You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by gu...@apache.org on 2017/10/23 08:10:33 UTC

[05/18] incubator-weex git commit: * [android] modify border-android.png

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java
index 782b16c..03f3057 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java
@@ -335,9 +335,7 @@ public class WXDomObject extends CSSNode implements Cloneable,ImmutableDomObject
 
     int index = mDomChildren.indexOf(child);
     if (index == -1) {
-      if (WXEnvironment.isApkDebugable()) {
         WXLogUtils.e("[WXDomObject] remove function error");
-      }
       return;
     }
     mDomChildren.remove(index).parent = null;
@@ -685,7 +683,7 @@ public class WXDomObject extends CSSNode implements Cloneable,ImmutableDomObject
             type = TextUtils.isEmpty(result.replacedComponent) ? WXBasicComponentType.DIV
                     : result.replacedComponent;
             json.put(TYPE, type);
-            if (WXEnvironment.isApkDebugable() && result.validateInfo != null) {
+            if (result.validateInfo != null) {
               String tag = "[WXDomObject]onComponentValidate failure. >>> " + result.validateInfo.toJSONString();
               WXLogUtils.e(tag);
             }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
index 9f35263..3fcedcb 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
@@ -96,9 +96,7 @@ public abstract class AbstractAddElementAction extends TraceableAction implement
     Stopwatch.split("parseDomObject");
 
     if (domObject == null || context.getDomByRef(domObject.getRef()) != null) {
-      if (WXEnvironment.isApkDebugable()) {
-        WXLogUtils.e("[DOMActionContextImpl] " + getStatementName() + " error,DOM object is null or already registered!!");
-      }
+      WXLogUtils.e("[DOMActionContextImpl] " + getStatementName() + " error,DOM object is null or already registered!!");
       instance.commitUTStab(IWXUserTrackAdapter.DOM_MODULE, errCode);
       return;
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/dom/action/MoveElementAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/MoveElementAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/MoveElementAction.java
index 258da68..bbd093c 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/MoveElementAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/MoveElementAction.java
@@ -91,5 +91,8 @@ final class MoveElementAction implements DOMAction, RenderAction {
     WXVContainer oldParent = component.getParent();
     oldParent.remove(component,false);
     ((WXVContainer) newParent).addChild(component, mNewIndex);
+    if(!component.isVirtualComponent()){
+      ((WXVContainer) newParent).addSubView(component.getHostView(), mNewIndex);
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/AbstractEditComponent.java
----------------------------------------------------------------------
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
index a8d1963..4ca9d50 100644
--- 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
@@ -221,6 +221,14 @@ public abstract class AbstractEditComponent extends WXComponent<WXEditText> {
 
           mBeforeText = s.toString();
 
+          if (getDomObject() != null && getDomObject().getAttrs() != null) {
+            Object val = getDomObject().getAttrs().get(Constants.Name.VALUE);
+            String valString = WXUtils.getString(val, null);
+            if (mBeforeText != null && mBeforeText.equals(valString)) {
+              return;
+            }
+          }
+
           if (!mIgnoreNextOnInputEvent) {
             fireEvent(Constants.Event.INPUT, s.toString());
           }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
----------------------------------------------------------------------
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
index bd6c2d7..082c14e 100644
--- 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
@@ -999,7 +999,9 @@ public abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
    * @param type
    */
   public void addEvent(String type) {
-    if (TextUtils.isEmpty(type) || mAppendEvents.contains(type)) {
+    if (TextUtils.isEmpty(type)
+            || mAppendEvents.contains(type)
+            || getRealView() == null) {
       return;
     }
     mAppendEvents.add(type);

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponentFactory.java
----------------------------------------------------------------------
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
index 4323821..4f9712f 100644
--- 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
@@ -59,11 +59,9 @@ public class WXComponentFactory {
 
     IFComponentHolder holder = WXComponentRegistry.getComponent(node.getType());
     if (holder == null) {
-      if (WXEnvironment.isApkDebugable()) {
         String tag = "WXComponentFactory error type:[" +
                 node.getType() + "]" + " 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){

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXImage.java
----------------------------------------------------------------------
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
index 1cf5d02..1c4d062 100644
--- 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
@@ -19,6 +19,7 @@
 package com.taobao.weex.ui.component;
 
 import android.Manifest;
+import android.app.Activity;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.RectF;
@@ -27,6 +28,7 @@ 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.widget.ImageView;
@@ -71,6 +73,7 @@ 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;
@@ -356,6 +359,13 @@ public class WXImage extends WXComponent<ImageView> {
   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);

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
----------------------------------------------------------------------
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
index 6cf784f..9e56259 100644
--- 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
@@ -233,7 +233,7 @@ public class WXScroller extends WXVContainer<ViewGroup> implements WXScrollViewL
    * Intercept refresh view and loading view
    */
   @Override
-  protected void addSubView(View child, int index) {
+  public void addSubView(View child, int index) {
     if (child == null || getRealView() == null) {
       return;
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java
----------------------------------------------------------------------
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
index 1023e3e..ec2d73f 100644
--- 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
@@ -173,7 +173,7 @@ public class WXSlider extends WXVContainer<FrameLayout> {
   }
 
   @Override
-  protected void addSubView(View view, int index) {
+  public void addSubView(View view, int index) {
     if (view == null || mAdapter == null) {
       return;
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSliderNeighbor.java
----------------------------------------------------------------------
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
index b1001b7..0899c8d 100644
--- 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
@@ -113,7 +113,7 @@ public class WXSliderNeighbor extends WXSlider {
     }
 
     @Override
-    protected void addSubView(View view, final int index) {
+    public void addSubView(View view, final int index) {
         if (view == null || mAdapter == null) {
             return;
         }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
----------------------------------------------------------------------
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
index e9263eb..62b667b 100644
--- 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
@@ -20,6 +20,9 @@ package com.taobao.weex.ui.component;
 
 import android.content.Context;
 import android.content.Intent;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.util.Pair;
 import android.support.annotation.Nullable;
 import android.util.Pair;
 import android.view.Menu;
@@ -309,7 +312,8 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
     }
   }
 
-  protected void addSubView(View child, int index) {
+  @RestrictTo(Scope.LIBRARY)
+  public void addSubView(View child, int index) {
     if (child == null || getRealView() == null) {
       return;
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
----------------------------------------------------------------------
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
index 640a17e..c04ed0a 100644
--- 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
@@ -150,6 +150,15 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
   private WXStickyHelper stickyHelper;
 
 
+
+  /**
+   * keep positon
+   * */
+  private  WXComponent keepPositionCell = null;
+  private  Runnable keepPositionCellRunnable = null;
+  private  long keepPositionLayoutDelay = 150;
+
+
   public BasicListComponent(WXSDKInstance instance, WXDomObject node, WXVContainer parent) {
     super(instance, node, parent);
     stickyHelper = new WXStickyHelper(this);
@@ -236,6 +245,9 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
     if (transforms != null) {
       bounceRecyclerView.getInnerView().addItemDecoration(RecyclerTransform.parseTransforms(getOrientation(), transforms));
     }
+    if(getDomObject().getAttrs().get(Constants.Name.KEEP_POSITION_LAYOUT_DELAY) != null){
+      keepPositionLayoutDelay = WXUtils.getNumberInt(getDomObject().getAttrs().get(Constants.Name.KEEP_POSITION_LAYOUT_DELAY), (int)keepPositionLayoutDelay);
+    }
 
     mItemAnimator=bounceRecyclerView.getInnerView().getItemAnimator();
 
@@ -245,6 +257,10 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
     bounceRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
     bounceRecyclerView.getInnerView().clearOnScrollListeners();
     bounceRecyclerView.getInnerView().addOnScrollListener(mViewOnScrollListener);
+    if(getDomObject().getAttrs().get(Constants.Name.HAS_FIXED_SIZE) != null){
+      boolean hasFixedSize = WXUtils.getBoolean(getDomObject().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) {
@@ -485,53 +501,54 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
       if (stickyComponent != null && stickyComponent.getDomObject() != null
           && stickyComponent instanceof WXCell) {
 
-        WXCell cell = (WXCell) stickyComponent;
-        if (cell.getHostView() == null) {
-          return;
-        }
+          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 fVisible = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
+            int firstVisiblePosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
+            int lastVisiblePosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
             int pos = mChildren.indexOf(cell);
             cell.setScrollPositon(pos);
-
-            if (pos <= fVisible) {
+            if (pos <= firstVisiblePosition
+                    || (cell.getStickyOffset() > 0 && firstVisiblePosition < pos && pos <= lastVisiblePosition  &&
+                    top <= cell.getStickyOffset())) {
               beforeFirstVisibleItem = true;
               if(pos > currentStickyPos) {
                 currentStickyPos = pos;
               }
-            }
-
-            if(pos > fVisible){
+            }else{
               removeOldSticky = true;
             }
           } else if(layoutManager instanceof StaggeredGridLayoutManager){
             int [] firstItems= new int[3];
-            int fVisible = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(firstItems)[0];
+            int firstVisiblePosition = ((StaggeredGridLayoutManager) layoutManager).findFirstVisibleItemPositions(firstItems)[0];
+            int lastVisiblePosition = ((StaggeredGridLayoutManager)  layoutManager).findLastVisibleItemPositions(firstItems)[0];
             int pos = mChildren.indexOf(cell);
 
-            if (pos <= fVisible) {
+            if (pos <= firstVisiblePosition || (cell.getStickyOffset() > 0 && firstVisiblePosition < pos && pos <= lastVisiblePosition  &&
+                    top <= cell.getStickyOffset())) {
               beforeFirstVisibleItem = true;
-            }
-
-            if(pos > fVisible){
+            }else{
               removeOldSticky = true;
             }
           }
 
-          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];
 
-          boolean showSticky = beforeFirstVisibleItem && cell.getLocationFromStart() >= 0 && top <= 0 && dy >= 0;
-          boolean removeSticky = cell.getLocationFromStart() <= 0 && top > 0 && dy <= 0;
+          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) {
@@ -584,7 +601,6 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
   @Override
   public void addChild(WXComponent child, int index) {
     super.addChild(child, index);
-
     if (child == null || index < -1) {
       return;
     }
@@ -593,7 +609,7 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
     bindViewType(child);
 
     int adapterPosition = index == -1 ? mChildren.size() - 1 : index;
-    T view = getHostView();
+    final T view = getHostView();
     if (view != null) {
       boolean isAddAnimation = false;
       ImmutableDomObject domObject = child.getDomObject();
@@ -616,9 +632,52 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
         }
       }
       if (isKeepScrollPosition) {
-        int last=((LinearLayoutManager)view.getInnerView().getLayoutManager()).findLastVisibleItemPosition();
-        view.getInnerView().getLayoutManager().scrollToPosition(last);
+        if(view.getInnerView().getLayoutManager() instanceof  LinearLayoutManager){
+            if(!view.getInnerView().isLayoutFrozen()){ //frozen, prevent layout when scroll
+                view.getInnerView().setLayoutFrozen(true);
+            }
+            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(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);
       }
@@ -628,6 +687,7 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
 
 
 
+
   private void relocateAppearanceHelper() {
     Iterator<Map.Entry<String, AppearanceHelper>> iterator = mAppearComponents.entrySet().iterator();
     while (iterator.hasNext()) {
@@ -646,7 +706,7 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
    * com.taobao.weex.ui.view.listview.WXRecyclerView}
    */
   @Override
-  protected void addSubView(View child, int index) {
+  public void addSubView(View child, int index) {
 
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/StickyHeaderHelper.java
----------------------------------------------------------------------
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
index 1534013..cedd86c 100644
--- 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
@@ -21,6 +21,7 @@ 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;
 
@@ -87,12 +88,20 @@ public class StickyHeaderHelper {
         if ((existedParent = (ViewGroup) headerView.getParent()) != null) {
           existedParent.removeView(headerView);
         }
+        headerView.setTag(headComponent.getRef());
         mParent.addView(headerView);
+        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.getDomObject().getEvents().contains("sticky")) {
         headComponent.fireEvent("sticky");
       }
@@ -108,7 +117,8 @@ public class StickyHeaderHelper {
 
 
     if(component == null || headerView == null){
-      WXLogUtils.e(" sticky header to remove not found."+compToRemove.getRef());
+      if(WXEnvironment.isApkDebugable()) {
+      }
       return;
     }
     if(mCurrentStickyRef != null && mCurrentStickyRef.equals(compToRemove.getRef())){
@@ -118,7 +128,12 @@ public class StickyHeaderHelper {
       @Override
       public void run() {
         mParent.removeView(headerView);
+        if(headerView.getVisibility() != View.VISIBLE){
+           headerView.setVisibility(View.VISIBLE);
+        }
         component.recoverySticky();
+        changeFrontStickyVisible();
+
       }
     }));
     if (component.getDomObject().getEvents().contains("unsticky")) {
@@ -141,6 +156,7 @@ public class StickyHeaderHelper {
         View view = mHeaderViews.get(cell.getRef());
         if(view != null){
           view.bringToFront();
+          changeFrontStickyVisible();
         }
       }
     }
@@ -148,4 +164,27 @@ public class StickyHeaderHelper {
       notifyStickyRemove(cell);
     }
   }
+
+
+  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);
+               }
+           }
+         }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java
----------------------------------------------------------------------
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
index 4fe4bc2..925da65 100644
--- 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
@@ -37,6 +37,9 @@ 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 static com.taobao.weex.common.Constants.Name.STICKY_OFFSET;
 
 /**
  * Root component for components in {@link WXListComponent}
@@ -55,12 +58,14 @@ public class WXCell extends WidgetContainer<WXFrameLayout> {
     private int mScrollPositon = -1;
     private boolean mFlatUIEnabled = false;
 
+
     private Object  renderData;
 
     private boolean isSourceUsed = false;
 
     private boolean hasLayout = false;
 
+
     @Deprecated
     public WXCell(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId, boolean isLazy) {
         super(instance, dom, parent);
@@ -142,28 +147,41 @@ public class WXCell extends WidgetContainer<WXFrameLayout> {
     }
 
     public void removeSticky() {
-        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) getDomObject().getLayoutWidth(),
-                (int) getDomObject().getLayoutHeight());
-        getHostView().addView(mTempStickyView, lp);
-        mHeadView.setTranslationX(headerViewOffsetX);
-        mHeadView.setTranslationY(headerViewOffsetY);
+        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) getDomObject().getLayoutWidth(),
+                    (int) getDomObject().getLayoutHeight());
+            getHostView().addView(mTempStickyView, lp);
+            mHeadView.setTranslationX(headerViewOffsetX);
+            mHeadView.setTranslationY(headerViewOffsetY);
+        }
     }
 
     public void recoverySticky() {
-        getHostView().removeView(mTempStickyView);
-        getHostView().addView(mHeadView);
-        mHeadView.setTranslationX(0);
-        mHeadView.setTranslationY(0);
+        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);
+            }
+            getHostView().removeView(mTempStickyView);
+            getHostView().addView(mHeadView);
+            mHeadView.setTranslationX(0);
+            mHeadView.setTranslationY(0);
+        }
     }
 
     @Override
@@ -185,6 +203,18 @@ public class WXCell extends WidgetContainer<WXFrameLayout> {
         return getInstance().getFlatUIContext().isFlatUIEnabled(this) && WXCell.class.equals(getClass()) && !isSticky();
     }
 
+    public int getStickyOffset(){
+        if(getDomObject() == null){
+            return  0;
+        }
+        WXDomObject domObject = (WXDomObject) getDomObject();
+        if(domObject.getAttrs().get(STICKY_OFFSET) == null){
+            return 0;
+        }
+        float  offset = WXUtils.getFloat(domObject.getAttrs().get(STICKY_OFFSET));
+        return (int)(WXViewUtils.getRealPxByWidth(offset,domObject.getViewPortWidth()));
+    }
+
     public Object getRenderData() {
         return renderData;
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
----------------------------------------------------------------------
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
index 7e0746b..76bcce0 100644
--- 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
@@ -593,7 +593,7 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp
      * com.taobao.weex.ui.view.listview.WXRecyclerView}
      */
     @Override
-    protected void addSubView(View child, int index) {
+    public void addSubView(View child, int index) {
 
     }
 
@@ -1306,7 +1306,7 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp
                     continue;
                 }
                 TemplateViewHolder itemHolder = (TemplateViewHolder) recyclerView.findViewHolderForAdapterPosition(position);
-                if(itemHolder == null){
+                if(itemHolder == null || itemHolder.getComponent() == null){
                     break;
                 }
                 List<WXComponent> childListeners = findChildListByRef(itemHolder.getComponent(), helper.getAwareChild().getRef());

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/ui/view/listview/WXRecyclerView.java
----------------------------------------------------------------------
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
index 20be140..b2a1793 100644
--- 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
@@ -42,6 +42,8 @@ public class WXRecyclerView extends RecyclerView implements WXGestureObservable
   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);
@@ -91,6 +93,7 @@ public class WXRecyclerView extends RecyclerView implements WXGestureObservable
     if(!scrollable) {
       return true;
     }
+    hasTouch = true;
     boolean result = super.onTouchEvent(event);
     if (mGesture != null) {
       result |= mGesture.onTouch(this, event);
@@ -110,26 +113,31 @@ public class WXRecyclerView extends RecyclerView implements WXGestureObservable
       }
       //Any else?
     } else {
+      smoothScrollToPosition(position);
       if (offset != 0) {
         setOnSmoothScrollEndListener(new ExtendedLinearLayoutManager.OnSmoothScrollEndListener() {
           @Override
           public void onStop() {
-            if (orientation == Constants.Orientation.VERTICAL) {
-                smoothScrollBy(0, offset);
-            } else {
-                smoothScrollBy(offset, 0);
-            }
+            post(new Runnable() {
+              @Override
+              public void run() {
+                if (orientation == Constants.Orientation.VERTICAL) {
+                  smoothScrollBy(0, offset);
+                } else {
+                  smoothScrollBy(offset, 0);
+                }
+              }
+            });
           }
         });
       }
-      smoothScrollToPosition(position);
     }
   }
 
   public void setOnSmoothScrollEndListener(final ExtendedLinearLayoutManager.OnSmoothScrollEndListener onSmoothScrollEndListener){
-    if(getLayoutManager() instanceof ExtendedLinearLayoutManager){
+    if(getLayoutManager() instanceof ExtendedLinearLayoutManager && !hasTouch){
        ExtendedLinearLayoutManager extendedLinearLayoutManager = (ExtendedLinearLayoutManager)getLayoutManager();
-       extendedLinearLayoutManager.setOnScrollEndListener(onSmoothScrollEndListener);
+      extendedLinearLayoutManager.setOnScrollEndListener(onSmoothScrollEndListener);
     }else{
       addOnScrollListener(new RecyclerView.OnScrollListener() {
         @Override

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java
----------------------------------------------------------------------
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
index 1f2b4b1..1f5b4b2 100644
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java
+++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java
@@ -71,13 +71,18 @@ public class WXLogUtils {
   }
 
   private static void log(String tag, String msg, LogLevel level){
-    if (WXEnvironment.isApkDebugable() && msg != null && WXEnvironment.sLogLevel.compare(level) >= 0) {
-      Log.println(level.getPriority(),tag, msg);
-      writeConsoleLog(level.getName(), msg);
-      sendLog(level, msg);
-    }
-    if (sLogWatcher != null) {
-      sLogWatcher.onLog(level.getName(), tag, msg);
+    if (msg != null && WXEnvironment.sLogLevel.compare(level) >= 0) {
+      if (sLogWatcher != null ) {
+        sLogWatcher.onLog(level.getName(), tag, msg);
+      }else{
+        Log.println(level.getPriority(),tag, msg);
+      }
+
+      // if not debug level then print log
+      if(WXEnvironment.isApkDebugable() && !level.getName().equals("debug")){
+		writeConsoleLog(level.getName(), msg);
+		sendLog(level, msg);
+	  }
     }
   }
 
@@ -114,13 +119,8 @@ public class WXLogUtils {
   }
 
   public static void d(String tag, String msg) {
-    if (!TextUtils.isEmpty(msg) && !TextUtils.isEmpty(tag)) {
-      log(tag, msg, LogLevel.DEBUG);
-    }
 
     if (WXEnvironment.isApkDebugable() && !TextUtils.isEmpty(msg) && WXEnvironment.sLogLevel.compare(LogLevel.DEBUG) >= 0) {
-      Log.d(tag, msg);
-
       if ("jsLog".equals(tag) && jsLogWatcher != null) {
         if (msg.endsWith("__DEBUG")) {
           jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__DEBUG", ""));
@@ -214,15 +214,13 @@ public class WXLogUtils {
   }
 
   public static void w(String prefix, Throwable e) {
-    if (WXEnvironment.isApkDebugable()) {
       w(prefix + getStackTrace(e));
-    }
+
   }
 
   public static void e(String prefix, Throwable e) {
-    if (WXEnvironment.isApkDebugable()) {
       e(prefix + getStackTrace(e));
-    }
+
   }
 
   public static void wtf(String prefix, Throwable e){

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/utils/WXSoInstallMgrSdk.java
----------------------------------------------------------------------
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
index a7fba8a..827cc94 100644
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXSoInstallMgrSdk.java
+++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXSoInstallMgrSdk.java
@@ -32,6 +32,7 @@ import com.taobao.weex.common.WXErrorCode;
 import com.taobao.weex.common.WXPerformance;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -68,6 +69,8 @@ public class WXSoInstallMgrSdk {
   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";
 
   private final static int ARMEABI_Size = 3583820;
   private final static int X86_Size = 4340864;
@@ -111,6 +114,9 @@ public class WXSoInstallMgrSdk {
       return false;
     }
 
+    // copy startup so
+    copyStartUpSo();
+
     boolean InitSuc = false;
     if (checkSoIsValid(libName, BuildConfig.ARMEABI_Size) ||checkSoIsValid(libName, BuildConfig.X86_Size)) {
 
@@ -170,6 +176,69 @@ public class WXSoInstallMgrSdk {
     return InitSuc;
   }
 
+  /**
+   * copyStartUpSo
+   */
+  public static void copyStartUpSo() {
+    try {
+      boolean installOnSdcard = true;
+      String pkgName = WXEnvironment.getApplication().getPackageName();
+      // cp weexjsb any way
+//      try {
+//        PackageManager pm = WXEnvironment.getApplication().getApplicationContext().getPackageManager();
+//        ApplicationInfo appInfo = pm.getApplicationInfo(pkgName, 0);
+//        if ((appInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+//          // App on sdcard
+//          installOnSdcard = true;
+//        }
+//      } catch (Throwable e) {
+//      }
+
+      if (installOnSdcard) {
+
+        String cacheFile = WXEnvironment.getApplication().getApplicationContext().getCacheDir().getPath();
+        // if android api < 16 copy libweexjst.so else copy libweexjsb.so
+        boolean pieSupport = true;
+        File newfile;
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+          pieSupport = false;
+          newfile = new File(cacheFile + STARTUPSOANDROID15);
+        } else {
+          newfile = new File(cacheFile + STARTUPSO);
+        }
+        if (newfile.exists()) {
+          return;
+        }
+
+        String path = "/data/data/" + pkgName + "/lib";
+        if (cacheFile != null && cacheFile.indexOf("/cache") > 0) {
+          path = cacheFile.replace("/cache", "/lib");
+        }
+
+        String soName;
+        if (pieSupport) {
+          soName = path + STARTUPSO;
+        } else {
+          soName = path + STARTUPSOANDROID15;
+        }
+
+        File oldfile = new File(soName);
+        if (oldfile.exists()) {
+          FileInputStream inputStream = new FileInputStream(oldfile);
+          byte[] data = new byte[1024];
+          FileOutputStream outputStream =new FileOutputStream(newfile);
+          while (inputStream.read(data) != -1) {
+            outputStream.write(data);
+          }
+          inputStream.close();
+          outputStream.close();
+        }
+      }
+    } catch (Throwable e) {
+      e.printStackTrace();
+    }
+  }
+
   private static String _getFieldReflectively(Build build, String fieldName) {
     try {
       final Field field = Build.class.getField(fieldName);

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java
----------------------------------------------------------------------
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
index 7d11d5a..4a1b304 100644
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java
+++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java
@@ -378,7 +378,7 @@ public class WXViewUtils {
   public static void clipCanvasWithinBorderBox(View targetView, Canvas canvas) {
     Drawable drawable;
     if (clipCanvasDueToAndroidVersion(canvas) &&
-        clipCanvasIfAnimationExist() &&
+        clipCanvasIfAnimationExist(targetView) &&
         ((drawable = targetView.getBackground()) instanceof BorderDrawable)) {
       BorderDrawable borderDrawable = (BorderDrawable) drawable;
       if (borderDrawable.isRounded()) {
@@ -394,7 +394,7 @@ public class WXViewUtils {
   public static void clipCanvasWithinBorderBox(Widget widget, Canvas canvas) {
     BorderDrawable borderDrawable;
     if (clipCanvasDueToAndroidVersion(canvas) &&
-        clipCanvasIfAnimationExist() &&
+        clipCanvasIfAnimationExist(null) &&
         (borderDrawable=widget.getBackgroundAndBorder())!=null ) {
       if (borderDrawable.isRounded() && clipCanvasIfBackgroundImageExist(widget, borderDrawable)) {
           Path path = borderDrawable.getContentPath(
@@ -424,8 +424,25 @@ public class WXViewUtils {
    * 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() {
-    return Build.VERSION.SDK_INT != VERSION_CODES.N;
+  private static boolean clipCanvasIfAnimationExist(View targetView) {
+    if (Build.VERSION.SDK_INT != VERSION_CODES.N) {
+      return true;
+    }
+    if(targetView != null &&
+            targetView.getScaleX() == 1 &&
+            targetView.getScaleY() == 1 &&
+            targetView.getTranslationX() == 0 &&
+            targetView.getTranslationY() == 0 &&
+            targetView.getRotation() == 0 &&
+            targetView.getRotationX() == 0 &&
+            targetView.getRotationY() == 0) {
+      if(Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && targetView.getTranslationZ() != 0 ) {
+        return false;
+      } else {
+        return true;
+      }
+    }
+    return false;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java
----------------------------------------------------------------------
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
index 3fde10a..e249c1c 100644
--- a/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java
+++ b/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java
@@ -20,6 +20,7 @@ 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;
@@ -91,4 +92,17 @@ public class WXLogUtilsTest {
     Log.e("tag",new Throwable("test"));
   }
 
-}
+  @Test
+  public void testLogLevel() throws Exception {
+    WXEnvironment.sLogLevel = LogLevel.DEBUG;
+    Log.d("LogLevel.DEBUG", "test debug");
+    Log.w("LogLevel.DEBUG", "test warning");
+    Log.e("LogLevel.DEBUG", "test error");
+
+    WXEnvironment.sLogLevel = LogLevel.WARN;
+
+    Log.d("LogLevel.WARN", "test debug");
+    Log.w("LogLevel.WARN", "test warning");
+    Log.e("LogLevel.WARN", "test error");
+  }
+  }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/sdk/src/test/java/com/taobao/weex/utils/WXUtilsTest.java
----------------------------------------------------------------------
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
index e981c69..5b6d273 100644
--- a/android/sdk/src/test/java/com/taobao/weex/utils/WXUtilsTest.java
+++ b/android/sdk/src/test/java/com/taobao/weex/utils/WXUtilsTest.java
@@ -19,6 +19,7 @@
 package com.taobao.weex.utils;
 
 import android.text.TextUtils;
+import android.util.Log;
 
 import com.taobao.weappplus_sdk.BuildConfig;
 import com.taobao.weex.WXEnvironment;
@@ -49,7 +50,7 @@ import static org.mockito.Matchers.any;
 @RunWith(PowerMockRunner.class)
 @Config(constants = BuildConfig.class, sdk = 19)
 @PowerMockIgnore( {"org.mockito.*", "org.robolectric.*", "android.*"})
-@PrepareForTest( {WXEnvironment.class, WXViewUtils.class, WXSDKInstance.class, TextUtils.class})
+@PrepareForTest( {WXEnvironment.class, WXViewUtils.class, WXSDKInstance.class, TextUtils.class, Log.class, WXUtils.class, WXLogUtils.class})
 public class WXUtilsTest extends TestCase {
 
     public static final float TEST_DENSITY = 3.0f;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/android/weex_debug/src/main/java/com/taobao/weex/bridge/WXWebsocketBridge.java
----------------------------------------------------------------------
diff --git a/android/weex_debug/src/main/java/com/taobao/weex/bridge/WXWebsocketBridge.java b/android/weex_debug/src/main/java/com/taobao/weex/bridge/WXWebsocketBridge.java
index b686f7c..1343f60 100644
--- a/android/weex_debug/src/main/java/com/taobao/weex/bridge/WXWebsocketBridge.java
+++ b/android/weex_debug/src/main/java/com/taobao/weex/bridge/WXWebsocketBridge.java
@@ -204,6 +204,21 @@ public class WXWebsocketBridge implements IWXBridge,WXWebSocketManager.JSDebugge
     }
 
     @Override
+    public int initFrameworkEnv(String scriptsFramework,WXParams params, String cacheDir, boolean pieSupport) {
+        if (!mInit) {
+            return -1;
+        }
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("method", "evalFramework");
+        ArrayList<String> args = new ArrayList<>();
+        args.add(scriptsFramework);
+        map.put("arguments", args);
+        WXWebSocketManager.getInstance().sendMessage(JSON.toJSONString(map));
+        return 0;
+    }
+
+    @Override
     public void takeHeapSnapshot(String filename) {}
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/dangerfile.js
----------------------------------------------------------------------
diff --git a/dangerfile.js b/dangerfile.js
index 97c4146..616f27a 100644
--- a/dangerfile.js
+++ b/dangerfile.js
@@ -273,6 +273,15 @@ filesToVerifySrcHeader.forEach(filepath => {
       return;
     }
   }
+
+  // check cn for source code
+  var reg = /[\u4e00-\u9FA5]+/; 
+  var res = reg.test(content);
+  if(res){
+    console.error("Code file "+ filepath +" has cn source code.");
+    fail("Code file "+ filepath +" has cn source code.");
+    return ;
+  }
 });
 
 
@@ -307,11 +316,12 @@ function findReviewer(resolve, reject) {
     number: danger.github.pr.number,
     headers: {Accept: 'application/vnd.github.diff',"user-agent": "node.js"}
   }, function (err, result) {
-    console.log('parseDeleteAndNormalLines')
     if ("undefined" === typeof result || "undefined" === typeof result.data || err) {
+      console.log('result:'+result+', error:'+err);
       resolve()
       return
     }
+    console.log('result:'+result);
     parseDeleteAndNormalLines(result.data, fileToDeletedLinesMap, fileToNormalLinesMap)
     console.log('getContent')
     var promises = danger.git.modified_files.map(function(file) {
@@ -366,21 +376,29 @@ function getContent(url) {
 
 function parseDeleteAndNormalLines(diffData, fileToDeletedLinesMap, fileToNormalLinesMap) {
   try {
+    console.log('parseDeleteAndNormalLines')
     var diffs = parseDiff(diffData)
-    diffs.forEach(diff => {
-      fileToDeletedLinesMap[diff.from] = [];
-      fileToNormalLinesMap[diff.from] = [];
-      diff.chunks.forEach(chunk => {
-        chunk.changes.forEach(change => {
-          if (change.del) {
-            fileToDeletedLinesMap[diff.from].push(change.ln)
-          }
-          if (change.normal) {
-            fileToNormalLinesMap[diff.from].push(change.ln1)
-          }
-        })
+    console.log('diffs:'+diffs)
+    if(diffs&&diffs instanceof Array){
+      diffs.forEach(diff => {
+        fileToDeletedLinesMap[diff.from] = [];
+        fileToNormalLinesMap[diff.from] = [];
+        if(diff&&diff.chunks&&diff.chunks instanceof Array){
+          diff.chunks.forEach(chunk => {
+            if(chunk&&chunk.changes&&chunk.changes instanceof Array){
+              chunk.changes.forEach(change => {
+                if (change&&change.del) {
+                  fileToDeletedLinesMap[diff.from].push(change.ln)
+                }
+                if (change&&change.normal) {
+                  fileToNormalLinesMap[diff.from].push(change.ln1)
+                }
+              })
+            }
+          })
+        }
       })
-    })
+    }
   } catch (error) {
     console.log(error)
   }
@@ -441,6 +459,7 @@ function findBlameReviewers(fileToDeletedLinesMap, fileToNormalLinesMap, fileToB
 
   console.log('blame point:', reviewers)
   var names = Object.keys(reviewers)
+  if(!names||!names instanceof Array||names.length<=0)return;
   names.sort((name1, name2) => {
     return reviewers[name1] > reviewers[name2] ? -1 : 1
   })

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/source/cn/guide/contributing.md
----------------------------------------------------------------------
diff --git a/doc/source/cn/guide/contributing.md b/doc/source/cn/guide/contributing.md
index 36db1f9..fd3138d 100644
--- a/doc/source/cn/guide/contributing.md
+++ b/doc/source/cn/guide/contributing.md
@@ -25,23 +25,24 @@ version: 2.1
 ## 分支管理 (英)
 
 ```
-master
+release
  ↑
-dev         <--- PR(hotfix/typo/3rd-PR)
- ↑ PR
-{domain}-feature-{date}
+{version}
+ ↑
+master         <--- PR(feature/hotfix/typo)
 ```
 
 0. `master` branch
-    0. `master` is the latest (pre-)release branch.
-0. `dev` branch
-    0. `dev` is the stable developing branch.
-    0. ***It's RECOMMENDED to commit hotfix (like typo) or feature PR to `dev`***.
-0. `{domain}-feature-{date}` branch
-    0. The branch for a developing iteration, e.g. `android-feature-20160607` is an android developing iteration which is done at 2016.06.07. `{domain}` consists of `android`, `ios`, `jsfm` and `html5`. 
-    0. **DO NOT commit any PR to such a branch**.
-
-### 分支命名
+    0. `master` is the stable developing branch.
+    0. ***It's RECOMMENDED to commit hotfix (like typo) or feature PR to `master `***.
+0. `{version}` branch
+    0. `{version}` is used for every version which we consider for stable publish.
+    0. e.g. `v0.16`
+0. `release` branch
+    0. `release` is the latest release branch,we will make tag and publish version on this branch.
+
+### 用于PR的分支命名
+
 
 ```
 {module}-{action}-{shortName}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/source/guide/contributing.md
----------------------------------------------------------------------
diff --git a/doc/source/guide/contributing.md b/doc/source/guide/contributing.md
index ea824f4..00cb979 100644
--- a/doc/source/guide/contributing.md
+++ b/doc/source/guide/contributing.md
@@ -25,23 +25,23 @@ Besides Weex dev mailing list, we also have some other mailing lists for you. Yo
 ## Branch Management
 
 ```
-master
+release
  ↑
-dev         <--- PR(hotfix/typo/3rd-PR)
- ↑ PR
-{domain}-feature-{date}
+{version}
+ ↑
+master         <--- PR(feature/hotfix/typo)
 ```
 
 0. `master` branch
-    0. `master` is the latest (pre-)release branch.
-0. `dev` branch
-    0. `dev` is the stable developing branch.
-    0. ***It's RECOMMENDED to commit hotfix (like typo) or feature PR to `dev`***.
-0. `{domain}-feature-{date}` branch
-    0. The branch for a developing iteration, e.g. `android-feature-20160607` is an android developing iteration which is done at 2016.06.07. `{domain}` consists of `android`, `ios`, `jsfm` and `html5`. 
-    0. **DO NOT commit any PR to such a branch**.
-
-### Branch Name 
+    0. `master` is the stable developing branch.
+    0. ***It's RECOMMENDED to commit hotfix (like typo) or feature PR to `master `***.
+0. `{version}` branch
+    0. `{version}` is used for every version which we consider for stable publish.
+    0. e.g. `v0.16`
+0. `release` branch
+    0. `release` is the latest release branch,we will make tag and publish version on this branch.
+
+### Branch Name For PR
 
 ```
 {module}-{action}-{shortName}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/source/references/platform-difference.md
----------------------------------------------------------------------
diff --git a/doc/source/references/platform-difference.md b/doc/source/references/platform-difference.md
new file mode 100644
index 0000000..0aadfae
--- /dev/null
+++ b/doc/source/references/platform-difference.md
@@ -0,0 +1,11 @@
+---
+title: Platform Differences Between Weex and Web
+type: references
+order: 12
+version: 2.1
+has_chapter_content: true
+---
+
+# Platform Differences Between Weex and Web
+
+Work in progresss.

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/source/references/platfrom-difference.md
----------------------------------------------------------------------
diff --git a/doc/source/references/platfrom-difference.md b/doc/source/references/platfrom-difference.md
deleted file mode 100644
index 0aadfae..0000000
--- a/doc/source/references/platfrom-difference.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: Platform Differences Between Weex and Web
-type: references
-order: 12
-version: 2.1
-has_chapter_content: true
----
-
-# Platform Differences Between Weex and Web
-
-Work in progresss.

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/source/references/vue/difference-with-web.md
----------------------------------------------------------------------
diff --git a/doc/source/references/vue/difference-with-web.md b/doc/source/references/vue/difference-with-web.md
index 2af11f9..b750591 100644
--- a/doc/source/references/vue/difference-with-web.md
+++ b/doc/source/references/vue/difference-with-web.md
@@ -9,7 +9,7 @@ version: 2.1
 
 ## Platform Differences
 
-Vue.js was designed for the Web platform at the begining. Although it can be based on Weex to develop native applications, there are still many differences between web and native. See [Platform Differences Between Weex and Web](../ platform-difference.html) for more details.
+Vue.js was designed for the Web platform at the begining. Although it can be based on Weex to develop native applications, there are still many differences between web and native. See [Platform Differences Between Weex and Web](../platform-difference.html) for more details.
 
 Due to those differences, Weex doesn't support those features in Vue.js (mostly are DOM-related):
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/themes/weex/layout/_partial/article.ejs
----------------------------------------------------------------------
diff --git a/doc/themes/weex/layout/_partial/article.ejs b/doc/themes/weex/layout/_partial/article.ejs
index 3ee5b2a..e7052b7 100644
--- a/doc/themes/weex/layout/_partial/article.ejs
+++ b/doc/themes/weex/layout/_partial/article.ejs
@@ -8,4 +8,6 @@
   <% if (page_type === 'article') { %>
      <%- partial('_partial/post/nav') %>
   <% } %>
+  <%- partial('footer') %>
+  <%- partial('after-footer') %>
 </article>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/themes/weex/layout/index.ejs
----------------------------------------------------------------------
diff --git a/doc/themes/weex/layout/index.ejs b/doc/themes/weex/layout/index.ejs
index 4a1ad87..b713fd4 100644
--- a/doc/themes/weex/layout/index.ejs
+++ b/doc/themes/weex/layout/index.ejs
@@ -250,6 +250,9 @@
   </div>
 </div>
 <a href="javascript:;" id="back2top" class="back2top"><span class="iconfont icon-arrow-small"></span></a>
+<%- partial('_partial/footer') %>
+<%- partial('_partial/after-footer') %>
+
 <%- js('js/swiper.min') %>
 <%- js('js/velocity.js') %>
 <script>

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/themes/weex/layout/layout.ejs
----------------------------------------------------------------------
diff --git a/doc/themes/weex/layout/layout.ejs b/doc/themes/weex/layout/layout.ejs
index df3b12b..ba6dee3 100644
--- a/doc/themes/weex/layout/layout.ejs
+++ b/doc/themes/weex/layout/layout.ejs
@@ -9,8 +9,6 @@
   <%- partial('_partial/sidebar', {post: page, page_type: page_type}) %>
   <%- body %>
   
-  <%- partial('_partial/footer') %>
-  <%- partial('_partial/after-footer') %>
   <%- js('js/reqwest.js') %>
   <%- js('js/common.js') %>
   <% if (config.docsearch.enable){ %>    

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/themes/weex/source/css/common.scss
----------------------------------------------------------------------
diff --git a/doc/themes/weex/source/css/common.scss b/doc/themes/weex/source/css/common.scss
index 10c25cf..d03be9f 100644
--- a/doc/themes/weex/source/css/common.scss
+++ b/doc/themes/weex/source/css/common.scss
@@ -17,9 +17,9 @@ html, body {
 }
 
 body {
-  background: $bg-gray;
+  background: $bg-white;
   // font-family: Exo,'-apple-system','Open Sans',HelveticaNeue-Light,'Helvetica Neue Light','Helvetica Neue','Hiragino Sans GB','Microsoft YaHei',Helvetica,Arial,sans-serif;
-  font-family: Lato, "Microsoft Jhenghei", "Hiragino Sans GB", "Microsoft YaHei", sans-serif,'-apple-system','Open Sans',HelveticaNeue-Light,'Helvetica Neue Light';
+  font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif;
   // font-family: 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', 'WenQuanYi Micro Hei',sans-serif;
   // font-size:62.5%;max-height:100%;
   font-size: 14px;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/themes/weex/source/css/partial/header.scss
----------------------------------------------------------------------
diff --git a/doc/themes/weex/source/css/partial/header.scss b/doc/themes/weex/source/css/partial/header.scss
index ac02f1a..a45d8f7 100644
--- a/doc/themes/weex/source/css/partial/header.scss
+++ b/doc/themes/weex/source/css/partial/header.scss
@@ -6,7 +6,7 @@
   padding: 0 40px;
   position: fixed;
   background-color: rgba(255, 255, 255, .95);
-  box-shadow: 3px 2px 4px 0 rgba(0,0,0,0.12);
+  box-shadow: 0 0 1px rgba(0,0,0,0.25);
   top: 0;
   left: 0;
   right: 0;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/themes/weex/source/css/post.scss
----------------------------------------------------------------------
diff --git a/doc/themes/weex/source/css/post.scss b/doc/themes/weex/source/css/post.scss
index f3a6544..370d90c 100644
--- a/doc/themes/weex/source/css/post.scss
+++ b/doc/themes/weex/source/css/post.scss
@@ -50,14 +50,15 @@
   }
 
   .doc-nav {
-    position: absolute;
+    position: fixed;
     top: 72px;
     left: 0;
     bottom: 0;
-    background: $bg-gray;
+    width: 260px;
+    padding: 40px 20px 60px 60px;
+    background: $bg-white;
     width: 300px;
     z-index: 999;
-    padding: 43px 15px 15px;
     overflow-x: hidden;
     overflow-y: auto;
   }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/doc/themes/weex/source/css/variable.scss
----------------------------------------------------------------------
diff --git a/doc/themes/weex/source/css/variable.scss b/doc/themes/weex/source/css/variable.scss
index 50e35cd..cbe4b12 100644
--- a/doc/themes/weex/source/css/variable.scss
+++ b/doc/themes/weex/source/css/variable.scss
@@ -6,7 +6,7 @@ $text-light-black: #333;
 $text-black: #333;
 $text-white: #fff;
 $text-gray: #999;
-$text-blue: #00BDFF;
+$text-blue: #088bc3;
 $bg-blue: $text-blue;
 $bg-light-blue: #23CEFD;
 $bg-white: #fff;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/html5/runtime/api/WeexInstance.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/WeexInstance.js b/html5/runtime/api/WeexInstance.js
new file mode 100644
index 0000000..2093f17
--- /dev/null
+++ b/html5/runtime/api/WeexInstance.js
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 Document from '../vdom/Document'
+import { isRegisteredModule, getModuleDescription } from './module'
+import { isRegisteredComponent } from './component'
+
+const moduleProxies = {}
+
+function setId (weex, id) {
+  Object.defineProperty(weex, '[[CurrentInstanceId]]', { value: id })
+}
+
+function getId (weex) {
+  return weex['[[CurrentInstanceId]]']
+}
+
+function moduleGetter (module, method, taskCenter) {
+  return (...args) => taskCenter.send('module', { module, method }, args)
+}
+
+export default class WeexInstance {
+  constructor (id, config) {
+    setId(this, id)
+    this.config = config || {}
+    this.document = new Document(id, this.config.bundleUrl)
+    this.requireModule = this.requireModule.bind(this)
+    this.isRegisteredModule = isRegisteredModule
+    this.isRegisteredComponent = isRegisteredComponent
+  }
+
+  requireModule (moduleName) {
+    const id = getId(this)
+    if (!(id && this.document && this.document.taskCenter)) {
+      console.error(`[JS Framework] invalid instance id "${id}"`)
+      return
+    }
+
+    // warn for unknown module
+    if (!isRegisteredModule(moduleName)) {
+      console.warn(`[JS Framework] using unregistered weex module "${moduleName}"`)
+      return
+    }
+
+    // create new module proxy
+    if (!moduleProxies[moduleName]) {
+      const moduleDefine = getModuleDescription(moduleName)
+      const taskCenter = this.document.taskCenter
+
+      // create registered module apis
+      const moduleApis = {}
+      for (const methodName in moduleDefine) {
+        Object.defineProperty(moduleApis, methodName, {
+          enumerable: true,
+          configurable: true,
+          get: () => moduleGetter(moduleName, methodName, taskCenter),
+          set (fn) {
+            if (typeof fn === 'function') {
+              return taskCenter.send('module', {
+                module: moduleName,
+                method: methodName
+              }, [fn])
+            }
+          }
+        })
+      }
+
+      // create module Proxy
+      if (typeof Proxy === 'function') {
+        moduleProxies[moduleName] = new Proxy(moduleApis, {
+          get (target, methodName) {
+            if (methodName in target) {
+              return target[methodName]
+            }
+            console.warn(`[JS Framework] using unregistered method "${moduleName}.${methodName}"`)
+            return moduleGetter(moduleName, methodName, taskCenter)
+          }
+        })
+      }
+      else {
+        moduleProxies[moduleName] = moduleApis
+      }
+    }
+
+    return moduleProxies[moduleName]
+  }
+
+  supports (condition) {
+    if (typeof condition !== 'string') return null
+
+    const res = condition.match(/^@(\w+)\/(\w+)(\.(\w+))?$/i)
+    if (res) {
+      const type = res[1]
+      const name = res[2]
+      const method = res[4]
+      switch (type) {
+        case 'module': return isRegisteredModule(name, method)
+        case 'component': return isRegisteredComponent(name)
+      }
+    }
+
+    return null
+  }
+
+  // registerStyleSheet (styles) {
+  //   if (this.document) {
+  //     this.document.registerStyleSheet(styles)
+  //   }
+  // }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/html5/runtime/api/component.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/component.js b/html5/runtime/api/component.js
new file mode 100644
index 0000000..8a56961
--- /dev/null
+++ b/html5/runtime/api/component.js
@@ -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.
+ */
+
+import { registerElement } from '../vdom/WeexElement'
+
+const weexComponents = {}
+
+/**
+ * Register native components information.
+ * @param {array} newComponents
+ */
+export function registerComponents (newComponents) {
+  if (Array.isArray(newComponents)) {
+    newComponents.forEach(component => {
+      if (!component) {
+        return
+      }
+      if (typeof component === 'string') {
+        weexComponents[component] = true
+      }
+      else if (typeof component === 'object' && typeof component.type === 'string') {
+        weexComponents[component.type] = component
+        registerElement(component.type, component.methods)
+      }
+    })
+  }
+}
+
+/**
+ * Check whether the component has been registered.
+ * @param {String} component name
+ */
+export function isRegisteredComponent (name) {
+  return !!weexComponents[name]
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/html5/runtime/api/init.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/init.js b/html5/runtime/api/init.js
index 024afa7..cad0179 100644
--- a/html5/runtime/api/init.js
+++ b/html5/runtime/api/init.js
@@ -18,8 +18,10 @@
  */
 
 import { init as initTaskHandler } from '../bridge/TaskCenter'
-import { registerElement } from '../vdom/WeexElement'
+import { registerModules } from './module'
+import { registerComponents } from './component'
 import { services, register, unregister } from './service'
+import WeexInstance from './WeexInstance'
 
 let frameworks
 let runtimeConfig
@@ -95,58 +97,61 @@ function createInstance (id, code, config, data) {
   config = JSON.parse(JSON.stringify(config || {}))
   config.env = JSON.parse(JSON.stringify(global.WXEnvironment || {}))
 
-  const context = {
-    config,
+  const weex = new WeexInstance(id, config)
+  Object.freeze(weex)
+
+  const runtimeEnv = {
+    weex,
+    config, // TODO: deprecated
     created: Date.now(),
     framework: bundleType
   }
-  context.services = createServices(id, context, runtimeConfig)
-  instanceMap[id] = context
+  runtimeEnv.services = createServices(id, runtimeEnv, runtimeConfig)
+  instanceMap[id] = runtimeEnv
 
-  if (process.env.NODE_ENV === 'development') {
-    console.debug(`[JS Framework] create an ${bundleType} instance`)
-  }
+  const runtimeContext = Object.create(null)
+  Object.assign(runtimeContext, runtimeEnv.services, { weex })
 
-  const fm = frameworks[bundleType]
-  if (!fm) {
+  const framework = runtimeConfig.frameworks[bundleType]
+  if (!framework) {
     return new Error(`invalid bundle type "${bundleType}".`)
   }
 
-  return fm.createInstance(id, code, config, data, context)
-}
-
-const methods = {
-  createInstance,
-  registerService: register,
-  unregisterService: unregister
+  // run create instance
+  if (typeof framework.prepareInstanceContext === 'function') {
+    const instanceContext = framework.prepareInstanceContext(runtimeContext)
+    return runInContext(code, instanceContext)
+  }
+  return framework.createInstance(id, code, config, data, runtimeEnv)
 }
 
 /**
- * Register methods which init each frameworks.
- * @param {string} methodName
+ * Run js code in a specific context.
+ * @param {string} code
+ * @param {object} context
  */
-function genInit (methodName) {
-  methods[methodName] = function (...args) {
-    if (methodName === 'registerComponents') {
-      checkComponentMethods(args[0])
-    }
-    for (const name in frameworks) {
-      const framework = frameworks[name]
-      if (framework && framework[methodName]) {
-        framework[methodName](...args)
-      }
-    }
+function runInContext (code, context) {
+  const keys = []
+  const args = []
+  for (const key in context) {
+    keys.push(key)
+    args.push(context[key])
   }
+
+  const bundle = `
+    (function (global) {
+      "use strict";
+      ${code}
+    })(Object.create(this))
+  `
+
+  return (new Function(...keys, bundle))(...args)
 }
 
-function checkComponentMethods (components) {
-  if (Array.isArray(components)) {
-    components.forEach((name) => {
-      if (name && name.type && name.methods) {
-        registerElement(name.type, name.methods)
-      }
-    })
-  }
+const methods = {
+  createInstance,
+  registerService: register,
+  unregisterService: unregister
 }
 
 /**
@@ -203,6 +208,27 @@ function adaptInstance (methodName, nativeMethodName) {
   }
 }
 
+/**
+ * Register methods which init each frameworks.
+ * @param {string} methodName
+ * @param {function} sharedMethod
+ */
+function adaptMethod (methodName, sharedMethod) {
+  methods[methodName] = function (...args) {
+    if (typeof sharedMethod === 'function') {
+      sharedMethod(...args)
+    }
+
+    // TODO: deprecated
+    for (const name in runtimeConfig.frameworks) {
+      const framework = runtimeConfig.frameworks[name]
+      if (framework && framework[methodName]) {
+        framework[methodName](...args)
+      }
+    }
+  }
+}
+
 export default function init (config) {
   runtimeConfig = config || {}
   frameworks = runtimeConfig.frameworks || {}
@@ -216,8 +242,9 @@ export default function init (config) {
     framework.init(config)
   }
 
-  // @todo: The method `registerMethods` will be re-designed or removed later.
-  ; ['registerComponents', 'registerModules', 'registerMethods'].forEach(genInit)
+  adaptMethod('registerComponents', registerComponents)
+  adaptMethod('registerModules', registerModules)
+  adaptMethod('registerMethods')
 
   ; ['destroyInstance', 'refreshInstance', 'receiveTasks', 'getRoot'].forEach(genInstance)
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/html5/runtime/api/module.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/module.js b/html5/runtime/api/module.js
new file mode 100644
index 0000000..df26b92
--- /dev/null
+++ b/html5/runtime/api/module.js
@@ -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.
+ */
+
+const weexModules = {}
+
+/**
+ * Register native modules information.
+ * @param {object} newModules
+ */
+export function registerModules (newModules) {
+  for (const name in newModules) {
+    if (!weexModules[name]) {
+      weexModules[name] = {}
+    }
+    newModules[name].forEach(method => {
+      if (typeof method === 'string') {
+        weexModules[name][method] = true
+      }
+      else {
+        weexModules[name][method.name] = method.args
+      }
+    })
+  }
+}
+
+/**
+ * Check whether the module or the method has been registered.
+ * @param {String} module name
+ * @param {String} method name (optional)
+ */
+export function isRegisteredModule (name, method) {
+  if (typeof method === 'string') {
+    return !!(weexModules[name] && weexModules[name][method])
+  }
+  return !!weexModules[name]
+}
+
+export function getModuleDescription (name) {
+  return weexModules[name]
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/html5/runtime/vdom/Element.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/Element.js b/html5/runtime/vdom/Element.js
index 6663b51..15837f2 100644
--- a/html5/runtime/vdom/Element.js
+++ b/html5/runtime/vdom/Element.js
@@ -409,7 +409,7 @@ export default class Element extends Node {
 
     if (!isStopPropagation
       && isBubble
-      && BUBBLE_EVENTS.includes(type)
+      && (BUBBLE_EVENTS.indexOf(type) !== -1)
       && this.parentNode
       && this.parentNode.fireEvent) {
       event.currentTarget = this.parentNode

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
index 8addaca..749cb8c 100644
--- a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
+++ b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
@@ -264,6 +264,10 @@
 		77E65A161C155EB5008B8775 /* WXTextComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A141C155EB5008B8775 /* WXTextComponent.m */; };
 		77E65A191C155F25008B8775 /* WXScrollerComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 77E65A171C155F25008B8775 /* WXScrollerComponent.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		77E65A1A1C155F25008B8775 /* WXScrollerComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 77E65A181C155F25008B8775 /* WXScrollerComponent.m */; };
+		841CD1031F9739890081196D /* WXExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 841CD1021F9739890081196D /* WXExceptionUtils.m */; };
+		841CD1051F974DFA0081196D /* WXExceptionUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 841CD1041F97399C0081196D /* WXExceptionUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		841CD1061F974DFA0081196D /* WXExceptionUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 841CD1041F97399C0081196D /* WXExceptionUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		841CD1071F974E000081196D /* WXExceptionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 841CD1021F9739890081196D /* WXExceptionUtils.m */; };
 		C401945E1E344E8300D19C31 /* WXFloatCompareTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C401945D1E344E8300D19C31 /* WXFloatCompareTests.m */; };
 		C41E1A971DC1FD15009C7F90 /* WXDatePickerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C41E1A951DC1FD15009C7F90 /* WXDatePickerManager.h */; };
 		C41E1A981DC1FD15009C7F90 /* WXDatePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C41E1A961DC1FD15009C7F90 /* WXDatePickerManager.m */; };
@@ -851,6 +855,8 @@
 		77E65A141C155EB5008B8775 /* WXTextComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXTextComponent.m; sourceTree = "<group>"; };
 		77E65A171C155F25008B8775 /* WXScrollerComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXScrollerComponent.h; sourceTree = "<group>"; };
 		77E65A181C155F25008B8775 /* WXScrollerComponent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXScrollerComponent.m; sourceTree = "<group>"; };
+		841CD1021F9739890081196D /* WXExceptionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXExceptionUtils.m; sourceTree = "<group>"; };
+		841CD1041F97399C0081196D /* WXExceptionUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WXExceptionUtils.h; sourceTree = "<group>"; };
 		C401945D1E344E8300D19C31 /* WXFloatCompareTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXFloatCompareTests.m; sourceTree = "<group>"; };
 		C41E1A951DC1FD15009C7F90 /* WXDatePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXDatePickerManager.h; sourceTree = "<group>"; };
 		C41E1A961DC1FD15009C7F90 /* WXDatePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXDatePickerManager.m; sourceTree = "<group>"; };
@@ -1082,6 +1088,8 @@
 				2AAFC1B41C48DFF70026D2FE /* WXSDKError.h */,
 				749DC2791D40827B009E1C91 /* WXMonitor.h */,
 				749DC27A1D40827B009E1C91 /* WXMonitor.m */,
+				841CD1041F97399C0081196D /* WXExceptionUtils.h */,
+				841CD1021F9739890081196D /* WXExceptionUtils.m */,
 			);
 			name = Monitor;
 			path = WeexSDK/Sources/Monitor;
@@ -1602,6 +1610,7 @@
 				DCA0EF641D6EED6F00CB18B9 /* WXGlobalEventModule.h in Headers */,
 				2A837AB21CD9DE9200AEDF03 /* WXLoadingComponent.h in Headers */,
 				DCA446271EFA5DAF00D0CFA8 /* WeexSDK.h in Headers */,
+				841CD1051F974DFA0081196D /* WXExceptionUtils.h in Headers */,
 				C42E8F9B1F39DF07001EBE9D /* WXTracingProtocol.h in Headers */,
 				7423899F1C32733800D748CA /* WXType.h in Headers */,
 				59A582FC1CF5B17B0081FD3E /* WXBridgeContext.h in Headers */,
@@ -1793,6 +1802,7 @@
 				DCA445D51EFA598200D0CFA8 /* WXComponent+PseudoClassManagement.h in Headers */,
 				DCA4460E1EFA5A7E00D0CFA8 /* WXLength.h in Headers */,
 				DCA445FA1EFA5A3A00D0CFA8 /* WXNavigatorModule.h in Headers */,
+				841CD1061F974DFA0081196D /* WXExceptionUtils.h in Headers */,
 				DCA446081EFA5A6A00D0CFA8 /* NSArray+Weex.h in Headers */,
 				74B81AE51F73C3E900D3A61D /* WXRecycleListDataManager.h in Headers */,
 				DCA445F21EFA5A2300D0CFA8 /* WXHeaderComponent.h in Headers */,
@@ -2200,6 +2210,7 @@
 				7463192A1C71B92600EFEBD4 /* WXModalUIModule.m in Sources */,
 				77D161501C02E3880010B15B /* WXUtility.m in Sources */,
 				74A4BA9F1CB3C0A100195969 /* WXHandlerFactory.m in Sources */,
+				841CD1031F9739890081196D /* WXExceptionUtils.m in Sources */,
 				C4E97D341F1EF46D00ABC314 /* WXTracingManager.m in Sources */,
 				742AD72F1DF98C45007DC46C /* WXResourceRequest.m in Sources */,
 				7461F8931CFB373100F62D44 /* WXLayer.m in Sources */,
@@ -2278,6 +2289,7 @@
 				DCA4455E1EFA55B300D0CFA8 /* WXFooterComponent.m in Sources */,
 				DCA4455F1EFA55B300D0CFA8 /* WXNavigationDefaultImpl.m in Sources */,
 				74B81AF21F73C3E900D3A61D /* WXJSASTParser.mm in Sources */,
+				841CD1071F974E000081196D /* WXExceptionUtils.m in Sources */,
 				DCA445601EFA55B300D0CFA8 /* WXURLRewriteDefaultImpl.m in Sources */,
 				DCA445611EFA55B300D0CFA8 /* WXPrerenderManager.m in Sources */,
 				DCA445631EFA55B300D0CFA8 /* WXPickerModule.m in Sources */,

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
index 7985fe5..24801cc 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
@@ -40,6 +40,7 @@
 #import "WXSDKInstance_private.h"
 #import "WXPrerenderManager.h"
 #import "WXTracingManager.h"
+#import "WXExceptionUtils.h"
 
 #define SuppressPerformSelectorLeakWarning(Stuff) \
 do { \
@@ -506,8 +507,10 @@ _Pragma("clang diagnostic pop") \
     WX_MONITOR_PERF_END(WXPTFrameworkExecute);
     
     if ([self.jsBridge exception]) {
-        NSString *message = [NSString stringWithFormat:@"JSFramework executes error: %@", [self.jsBridge exception]];
-        WX_MONITOR_FAIL(WXMTJSFramework, WX_ERR_JSFRAMEWORK_EXECUTE, message);
+        NSString *exception = [[self.jsBridge exception] toString];
+        NSMutableString *errMsg = [NSMutableString stringWithFormat:@"[WX_KEY_EXCEPTION_SDK_INIT_JSFM_INIT_FAILED] %@",exception];
+        [WXExceptionUtils commitCriticalExceptionRT:@"WX_KEY_EXCEPTION_SDK_INIT" errCode:[NSString stringWithFormat:@"%d", WX_KEY_EXCEPTION_SDK_INIT] function:@"" exception:errMsg extParams:nil];
+        WX_MONITOR_FAIL(WXMTJSFramework, WX_ERR_JSFRAMEWORK_EXECUTE, errMsg);
     } else {
         WX_MONITOR_SUCCESS(WXMTJSFramework);
         //the JSFramework has been load successfully.
@@ -568,8 +571,10 @@ _Pragma("clang diagnostic pop") \
         [self.jsBridge executeJavascript:script];
         
         if ([self.jsBridge exception]) {
-            NSString *message = [NSString stringWithFormat:@"JSService executes error: %@", [self.jsBridge exception]];
-            WX_MONITOR_FAIL(WXMTJSService, WX_ERR_JSFRAMEWORK_EXECUTE, message);
+            NSString *exception = [[self.jsBridge exception] toString];
+            NSMutableString *errMsg = [NSMutableString stringWithFormat:@"[WX_KEY_EXCEPTION_INVOKE_JSSERVICE_EXECUTE] %@",exception];
+            [WXExceptionUtils commitCriticalExceptionRT:@"WX_KEY_EXCEPTION_INVOKE" errCode:[NSString stringWithFormat:@"%d", WX_KEY_EXCEPTION_INVOKE] function:@"" exception:errMsg extParams:nil];
+            WX_MONITOR_FAIL(WXMTJSService, WX_ERR_JSFRAMEWORK_EXECUTE, errMsg);
         } else {
             // success
         }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
index ec81b22..f076817 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
@@ -36,6 +36,7 @@
 #import "WXSDKManager.h"
 #import "WXExtendCallNativeManager.h"
 #import "WXTracingManager.h"
+#import "WXExceptionUtils.h"
 
 #import <dlfcn.h>
 
@@ -154,14 +155,17 @@
         
         _jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception){
             context.exception = exception;
-            NSString *message = [NSString stringWithFormat:@"[%@:%@:%@] %@\n%@", exception[@"sourceURL"], exception[@"line"], exception[@"column"], exception, [exception[@"stack"] toObject]];
-            id<WXJSExceptionProtocol> jsExceptionHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXJSExceptionProtocol)];
             
             WXSDKInstance *instance = [WXSDKEngine topInstance];
-            WXJSExceptionInfo * jsExceptionInfo = [[WXJSExceptionInfo alloc] initWithInstanceId:instance.instanceId bundleUrl:[instance.scriptURL absoluteString] errorCode:[NSString stringWithFormat:@"%d", WX_ERR_JS_EXECUTE] functionName:@"" exception:[NSString stringWithFormat:@"[%@:%@] %@\n%@ \njsMainBundleStringContentLength:%@\njsMainBundleStringContentMd5:%@",exception[@"line"], exception[@"column"],[exception toString], exception[@"stack"], instance.userInfo[@"jsMainBundleStringContentLength"]?:@"",instance.userInfo[@"jsMainBundleStringContentMd5"]?:@""] userInfo:nil];
-            if ([jsExceptionHandler respondsToSelector:@selector(onJSException:)]) {
-                [jsExceptionHandler onJSException:jsExceptionInfo];
-            }
+            NSString *bundleUrl = [instance.scriptURL absoluteString]?:@"WX_KEY_EXCEPTION_WXBRIDGE";
+            NSString *errorCode = [NSString stringWithFormat:@"%d", WX_KEY_EXCEPTION_WXBRIDGE];
+            NSString *message = [NSString stringWithFormat:@"[WX_KEY_EXCEPTION_WXBRIDGE] [%@:%@:%@] %@\n%@", exception[@"sourceURL"], exception[@"line"], exception[@"column"], [exception toString], [exception[@"stack"] toObject]];
+            NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                instance.userInfo[@"jsMainBundleStringContentLength"]?:@"",@"jsMainBundleStringContentLength",
+                instance.userInfo[@"jsMainBundleStringContentMd5"]?:@"",@"jsMainBundleStringContentMd5",nil];
+            WXJSExceptionInfo * jsExceptionInfo = [[WXJSExceptionInfo alloc] initWithInstanceId:instance.instanceId bundleUrl:bundleUrl errorCode:errorCode functionName:@"" exception:message userInfo:userInfo];
+            
+            [WXExceptionUtils commitCriticalExceptionRT:jsExceptionInfo];
             WX_MONITOR_FAIL(WXMTJSBridge, WX_ERR_JS_EXECUTE, message);
             if (instance.onJSRuntimeException) {
                 instance.onJSRuntimeException(jsExceptionInfo);

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/28dd9f3b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
index 48eda1a..929dd1a 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
@@ -662,8 +662,8 @@ typedef NS_ENUM(NSInteger, Direction) {
     
     if (_sliderChangeEvent) {
         [self fireEvent:@"change" params:@{@"index":@(index)} domChanges:@{@"attrs": @{@"index": @(index)}}];
-        self.currentIndex = index;
     }
+    self.currentIndex = index;
 }
 
 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView