From 268b49948394dab83579a1a2b769d8a52f289ca2 Mon Sep 17 00:00:00 2001 From: sospartan Date: Tue, 28 Feb 2017 15:34:15 +0800 Subject: [PATCH 1/9] * [android] fix domobject NPE --- .../taobao/weex/ui/view/refresh/wrapper/BaseBounceView.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 index e517ab1bd1..1809a78d02 100644 --- 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 @@ -213,6 +213,7 @@ import android.widget.FrameLayout; import com.taobao.weex.common.Constants; +import com.taobao.weex.dom.ImmutableDomObject; import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.ui.view.WXLoadingLayout; import com.taobao.weex.ui.view.WXRefreshLayout; @@ -329,8 +330,9 @@ public void setHeaderView(WXComponent refresh) { public void setFooterView(WXComponent loading) { setLoadmoreEnable(true); if (swipeLayout != null) { - if (swipeLayout.getFooterView() != null) { - swipeLayout.setLoadingHeight((int) loading.getDomObject().getLayoutHeight()); + ImmutableDomObject domObject; + if (swipeLayout.getFooterView() != null && (domObject = loading.getDomObject()) != null) { + swipeLayout.setLoadingHeight((int) domObject.getLayoutHeight()); String colorStr = (String) loading.getDomObject().getStyles().get(Constants.Name.BACKGROUND_COLOR); String bgColor = WXUtils.getString(colorStr, null); From 58d009d63c97d94c6070311fa33800980822f060 Mon Sep 17 00:00:00 2001 From: xkli <569664668@qq.com> Date: Tue, 28 Feb 2017 16:00:07 +0800 Subject: [PATCH 2/9] * [android] update list add attr keep-scroll-position (#2793) * * [android] update list add attr keep-scroll-position * * [android] update list add attr animation * * [android] update list * * [android] update modify judgment * * [android] add commit * * [android] update formate code --- .../com/taobao/weex/common/Constants.java | 8 ++ .../ui/component/list/BasicListComponent.java | 74 ++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) 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 index f297b6d0a3..e6e61e9a46 100755 --- a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java +++ b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java @@ -273,6 +273,8 @@ public interface Name { String POSITION = "position"; + String KEEP_SCROLL_POSITION = "keepScrollPosition"; + String TEXT_DECORATION = "textDecoration"; String TEXT_ALIGN = "textAlign"; String FONT_WEIGHT = "fontWeight"; @@ -347,6 +349,9 @@ public interface Name { String RETURN_KEY_TYPE = "returnKeyType"; String OFFSET = "offset"; String ANIMATED = "animated"; + + String INSERT_CELL_ANIMATION = "insertAnimation"; + String DELETE_CELL_ANIMATION = "deleteAnimation"; } public interface Value { @@ -381,6 +386,9 @@ public interface Value { String DIRECTION_RIGHT = "right"; String DIRECTION_UP = "up"; String DIRECTION_DOWN = "down"; + + String NONE = "none"; + String DEFAULT = "default"; } public interface Event { 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 65993f4ea9..eb7fd78630 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 @@ -231,6 +231,7 @@ import com.taobao.weex.common.Constants; import com.taobao.weex.common.OnWXScrollListener; import com.taobao.weex.common.WXRuntimeException; +import com.taobao.weex.dom.ImmutableDomObject; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.ui.component.AppearanceHelper; import com.taobao.weex.ui.component.Scrollable; @@ -288,6 +289,8 @@ public abstract class BasicListComponent(this); recyclerViewBaseAdapter.setHasStableIds(true); bounceRecyclerView.setRecyclerViewBaseAdapter(recyclerViewBaseAdapter); @@ -752,11 +757,54 @@ public void addChild(WXComponent child, int index) { int adapterPosition = index == -1 ? mChildren.size() - 1 : index; T view = getHostView(); if (view != null) { - view.getRecyclerViewBaseAdapter().notifyItemInserted(adapterPosition); + boolean isAddAnimation = isAddAnimation(child); + if (isAddAnimation) { + view.getInnerView().setItemAnimator(mItemAnimator); + } else { + view.getInnerView().setItemAnimator(null); + } + boolean isKeepScrollPosition = isKeepScrollPosition(child); + if (isKeepScrollPosition) { + view.getRecyclerViewBaseAdapter().notifyItemInserted(adapterPosition); + } else { + view.getRecyclerViewBaseAdapter().notifyItemChanged(adapterPosition); + } } relocateAppearanceHelper(); } + /** + * To determine whether an animation is needed + * @param child + * @return + */ + private boolean isAddAnimation(WXComponent child) { + ImmutableDomObject domObject = child.getDomObject(); + if (domObject != null) { + Object attr = domObject.getAttrs().get(Constants.Name.INSERT_CELL_ANIMATION); + if (Constants.Value.DEFAULT.equals(attr)) { + return true; + } + } + return false; + } + + /** + * Determine if the component needs to be fixed at the time of insertion + * @param child Need to insert the component + * @return fixed=true + */ + private boolean isKeepScrollPosition(WXComponent child) { + ImmutableDomObject domObject = child.getDomObject(); + if (domObject != null) { + Object attr = domObject.getAttrs().get(Constants.Name.KEEP_SCROLL_POSITION); + if (WXUtils.getBoolean(attr, false)) { + return true; + } + } + return false; + } + private void relocateAppearanceHelper() { Iterator> iterator = mAppearComponents.entrySet().iterator(); @@ -800,6 +848,14 @@ public void remove(WXComponent child, boolean destroy) { if (view == null) { return; } + + boolean isRemoveAnimation = isRemoveAnimation(child); + 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); @@ -807,6 +863,22 @@ public void remove(WXComponent child, boolean destroy) { super.remove(child, destroy); } + /** + * To determine whether an animation is needed + * @param child + * @return + */ + private boolean isRemoveAnimation(WXComponent child) { + ImmutableDomObject domObject = child.getDomObject(); + if (domObject != null) { + Object attr = domObject.getAttrs().get(Constants.Name.DELETE_CELL_ANIMATION); + if (Constants.Value.DEFAULT.equals(attr)) { + return true; + } + } + return false; + } + @Override public void computeVisiblePointInViewCoordinate(PointF pointF) { From 5a03143102c4ebffaace8e1cbe6e19e7857f7358 Mon Sep 17 00:00:00 2001 From: YorkShen Date: Tue, 28 Feb 2017 17:01:01 +0800 Subject: [PATCH 3/9] * [android] Fix https://github.com/alibaba/weex/issues/2125 (#2462) Fix the problem of mixing animation and border-radius together. --- .../ui/animation/BackgroundColorProperty.java | 252 ++++++++++++++++++ .../weex/ui/animation/WXAnimationModule.java | 4 +- 2 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 android/sdk/src/main/java/com/taobao/weex/ui/animation/BackgroundColorProperty.java 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 new file mode 100644 index 0000000000..5ef0eb1b64 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/animation/BackgroundColorProperty.java @@ -0,0 +1,252 @@ +/* + * + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "[]" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2016 Alibaba Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.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 { + + 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/WXAnimationModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/animation/WXAnimationModule.java index 3c037d4bbb..f3b03e1487 100755 --- 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 @@ -309,12 +309,12 @@ ObjectAnimator createAnimator(@NonNull WXAnimationBean animation, final View tar BorderDrawable borderDrawable; if ((borderDrawable=WXViewUtils.getBorderDrawable(target))!=null) { holders.add(PropertyValuesHolder.ofObject( - WXAnimationBean.Style.BACKGROUND_COLOR, new ArgbEvaluator(), + new BackgroundColorProperty(), new ArgbEvaluator(), borderDrawable.getColor(), WXResourceUtils.getColor(style.backgroundColor))); } else if (target.getBackground() instanceof ColorDrawable) { holders.add(PropertyValuesHolder.ofObject( - WXAnimationBean.Style.BACKGROUND_COLOR, new ArgbEvaluator(), + new BackgroundColorProperty(), new ArgbEvaluator(), ((ColorDrawable) target.getBackground()).getColor(), WXResourceUtils.getColor(style.backgroundColor))); } From fc11bc58c4813be8f68bb696bf920e1980107bfd Mon Sep 17 00:00:00 2001 From: YorkShen Date: Tue, 28 Feb 2017 20:05:31 +0800 Subject: [PATCH 4/9] * [android] Fix linear-gradient & border-radius & clipPath cannot work together if system version is 4.3 or 4.4. (#2759) Without this fix, the border-radius of linear-gradient div in the following page will not work. http://dotwe.org/weex/963c9ade129f86757cecdd85651cd30e This is mostly likely due to OpenGL ES 3.1, which provided "Separate shader objects" is not supported until android 5.0. --- .../weex/ui/view/border/BorderDrawable.java | 4 ++ .../com/taobao/weex/utils/WXViewUtils.java | 71 +++++++++++++++---- 2 files changed, 62 insertions(+), 13 deletions(-) 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 index 174b4f7f05..dd5f96dfce 100755 --- 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 @@ -455,6 +455,10 @@ public void setImage(Shader shader){ invalidateSelf(); } + public boolean hasImage(){ + return mShader!=null; + } + public boolean isRounded() { return mBorderRadius != null && (!FloatUtil.floatsEqual(getBorderRadius(mBorderRadius, BORDER_TOP_LEFT_RADIUS), 0) || 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 3dd5bcc707..e075ee803c 100755 --- a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java +++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java @@ -216,6 +216,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; +import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import com.taobao.weex.WXEnvironment; @@ -535,22 +536,66 @@ else if(drawable instanceof LayerDrawable){ public static void clipCanvasWithinBorderBox(View targetView, Canvas canvas) { Drawable drawable; - /* 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. - */ - /** - * 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 or higher. - */ - if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 || !canvas.isHardwareAccelerated()) && - Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && + if (clipCanvasDueToAndroidVersion(canvas) && + clipCanvasIfAnimationExist() && ((drawable = targetView.getBackground()) instanceof BorderDrawable)) { BorderDrawable borderDrawable = (BorderDrawable) drawable; - if(borderDrawable.isRounded()) { - Path path = borderDrawable.getContentPath( - new RectF(0, 0, targetView.getWidth(), targetView.getHeight())); - canvas.clipPath(path); + if (borderDrawable.isRounded()) { + if (clipCanvasIfBackgroundImageExist(targetView, borderDrawable)) { + Path path = borderDrawable.getContentPath( + new RectF(0, 0, targetView.getWidth(), targetView.getHeight())); + canvas.clipPath(path); + } + } + } + } + + /** + * 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. + * As the compile version of weex_sdk is 23, so API level 24 has to be hard-code. + */ + private static boolean clipCanvasIfAnimationExist() { + return Build.VERSION.SDK_INT != 24; + } + + /** + * 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; } } From eaf7a2561d01fa7ca14330ab133b5176b65b428c Mon Sep 17 00:00:00 2001 From: sospartan zheng Date: Wed, 1 Mar 2017 09:57:18 +0800 Subject: [PATCH 5/9] * [test] run android&js ci in linux (#2820) * * [test] run android&js ci in linux * * [test] update travis --- .travis.yml | 48 +++++++++++++++++++++++++++++++++++++++-------- test/ci-funcs.sh | 49 +++++++++++++++++++++++++++--------------------- 2 files changed, 68 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2531dbb2e0..09416c496c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,47 @@ -language: objective-c +os: + - osx + - linux +language: ruby rvm: 2.0.0 -osx_image: xcode8.2 -jdk: oraclejdk8 env: - matrix: - - TEST_SUITE=android - - TEST_SUITE=ios - - TEST_SUITE=danger - - TEST_SUITE=jsfm + - TEST_SUITE=ios + - TEST_SUITE=danger + - TEST_SUITE=jsfm + - TEST_SUITE=android matrix: fast_finish: true + exclude: + - os: linux + env: TEST_SUITE=ios + - os: linux + env: TEST_SUITE=danger + - os: osx + env: TEST_SUITE=jsfm + - os: osx + env: TEST_SUITE=android + - os: osx + env: TEST_SUITE=ios + - os: linux + env: TEST_SUITE=android + include: + - os: osx + env: TEST_SUITE=ios + osx_image: xcode8.2 + language: objective-c + - os: linux + env: TEST_SUITE=android + jdk: oraclejdk8 + language: android + android: + components: + - platform-tools + - tools + - build-tools-23.0.2 + - android-23 + - android-19 + - extra-google-m2repository + - extra-android-m2repository + - sys-img-armeabi-v7a-android-21 cache: directories: - node_modules diff --git a/test/ci-funcs.sh b/test/ci-funcs.sh index 9c7001902b..5a4c96a1cc 100644 --- a/test/ci-funcs.sh +++ b/test/ci-funcs.sh @@ -1,14 +1,14 @@ function installAndroidSDK { - brew install android-sdk - export ANDROID_HOME=/usr/local/opt/android-sdk - export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools - echo yes | android update sdk --all --no-ui --force -t 2 #platform tools - echo yes | android update sdk --all --no-ui --force -t 1 #tools - echo yes | android update sdk --all --no-ui --force -t 11 #build-tool - echo yes | android update sdk --all --no-ui --force -t 39 #sdk android-19 - echo yes | android update sdk --all --no-ui --force -t 35 #sdk android-23 - echo yes | android update sdk --all --no-ui --force -t 96 #sys-img - echo yes | android update sdk --all --no-ui --force -t 160 #support + # brew install android-sdk + # export ANDROID_HOME=/usr/local/opt/android-sdk + # export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools + echo yes | android update sdk --all --no-ui --force -t platform-tools #platform tools + echo yes | android update sdk --all --no-ui --force -t tools #tools + echo yes | android update sdk --all --no-ui --force -t build-tools-23.0.2 #build-tool + echo yes | android update sdk --all --no-ui --force -t android-19 #sdk android-19 + echo yes | android update sdk --all --no-ui --force -t android-23 #sdk android-23 + echo yes | android update sdk --all --no-ui --force -t sys-img-armeabi-v7a-android-21 #sys-img + echo yes | android update sdk --all --no-ui --force -t extra-android-m2repository #support } function createAVD { @@ -38,22 +38,29 @@ function setup_cpt { target=${1:-$target_android} + setupBasic + if [ $target = $target_android ]; then - setupBasic - installAndroidSDK - JAVA_HOME=$(/usr/libexec/java_home) npm install -g macaca-android + # setupBasic + # installAndroidSDK + npm install -g macaca-cli + npm install -g macaca-android createAVD startAVD & npm install export DISPLAY=:99.0 elif [ $target = $target_ios ] then - setupBasic + # setupBasic + npm install -g macaca-cli + brew update + brew install ios-webkit-debug-proxy npm install -g macaca-ios npm install gem install danger danger-xcode_summary xcpretty xcpretty-json-formatter elif [ $target = $target_jsfm ] then + # setupBasic npm install else gem install danger danger-xcode_summary xcpretty xcpretty-json-formatter @@ -61,13 +68,13 @@ function setup_cpt { } function setupBasic { - brew update - brew install nvm + curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash + export NVM_DIR="$HOME/.nvm" + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" export CHROME_BIN=chromium-browser - source $(brew --prefix nvm)/nvm.sh nvm install 7.0.0 - brew install ios-webkit-debug-proxy - npm install -g macaca-cli + nvm use 7.0.0 + } function printEnvInfo { @@ -89,10 +96,10 @@ function test_cpt { if [ $target = $target_android ]; then ./test/serve.sh 2&>1 > /dev/null & - export ANDROID_HOME=/usr/local/opt/android-sdk + # export ANDROID_HOME=/usr/local/opt/android-sdk cd android && ./run-ci.sh && cd $TRAVIS_BUILD_DIR waitForEmulator - JAVA_HOME=$(/usr/libexec/java_home) run_in_ci=true ./test/run.sh + run_in_ci=true ./test/run.sh elif [ $target = $target_ios ] then ./test/serve.sh 2&>1 > /dev/null & From 64b0edd090484063aea28c3c2c1500c102edb94c Mon Sep 17 00:00:00 2001 From: sospartan zheng Date: Wed, 1 Mar 2017 10:03:33 +0800 Subject: [PATCH 6/9] * [android] fix remove 'fixed' comp (#2744) --- .../java/com/taobao/weex/ui/component/WXComponent.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 cd7a11ba52..73bbd16075 100755 --- 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 @@ -1299,10 +1299,13 @@ public void destroy() { } removeAllEvent(); removeStickyStyle(); - if (mDomObj != null) { - mDomObj = null; + + View view; + if(mDomObj.isFixed() && (view = getHostView()) != null){ + getInstance().removeFixedView(view); } + mDomObj = null; mIsDestroyed = true; } From 91e884e03d779e2af42c98180d054fe587b8292b Mon Sep 17 00:00:00 2001 From: dreaming Date: Wed, 1 Mar 2017 10:09:39 +0800 Subject: [PATCH 7/9] load weex js with file scheme (#2743) * load weex js with file scheme * rename method name --- .../java/com/taobao/weex/WXSDKInstance.java | 2 +- .../com/taobao/weex/utils/WXFileUtils.java | 37 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java index 70c680240b..7c0ba9b268 100755 --- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java +++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java @@ -570,7 +570,7 @@ private void renderByUrlInternal(String pageName, Uri uri = Uri.parse(url); if (uri != null && TextUtils.equals(uri.getScheme(), "file")) { - render(pageName, WXFileUtils.loadAsset(assembleFilePath(uri), mContext), renderOptions, jsonInitData, flag); + render(pageName, WXFileUtils.loadFileOrAsset(assembleFilePath(uri), mContext), renderOptions, jsonInitData, flag); return; } 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 index d4269fd320..ebbe87bf68 100755 --- a/android/sdk/src/main/java/com/taobao/weex/utils/WXFileUtils.java +++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXFileUtils.java @@ -208,6 +208,9 @@ import android.text.TextUtils; import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -215,6 +218,29 @@ 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 @@ -226,9 +252,18 @@ public static String loadAsset(String path, Context context) { return null; } InputStream inputStream = null; - BufferedReader bufferedReader = null; try { inputStream = context.getAssets().open(path); + return readStreamToString(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + return ""; + } + + private 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]; From fa1c8b085e3fdaa213d817fbac2c2f479f3f1fb6 Mon Sep 17 00:00:00 2001 From: xkli <569664668@qq.com> Date: Wed, 1 Mar 2017 10:11:45 +0800 Subject: [PATCH 8/9] * [android] update WXStreamModule Determine whether the header is empty (#2753) --- .../com/taobao/weex/http/WXStreamModule.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) 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 index 841878ee9c..b6d3896144 100755 --- a/android/sdk/src/main/java/com/taobao/weex/http/WXStreamModule.java +++ b/android/sdk/src/main/java/com/taobao/weex/http/WXStreamModule.java @@ -205,15 +205,16 @@ package com.taobao.weex.http; import android.net.Uri; + import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.taobao.weex.WXEnvironment; 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.annotation.JSMethod; import com.taobao.weex.common.WXModule; import com.taobao.weex.common.WXRequest; import com.taobao.weex.common.WXResponse; @@ -507,20 +508,23 @@ public void onHttpUploadProgress(int uploadProgress) { @Override public void onHeadersReceived(int statusCode,Map> headers) { - mResponse.put("readyState",2); - mResponse.put("status",statusCode); - - Iterator>> it = headers.entrySet().iterator(); - Map simpleHeaders = new HashMap<>(); - while(it.hasNext()){ - Map.Entry> entry = it.next(); - if(entry.getValue().size()>0) - simpleHeaders.put(entry.getKey()==null?"_":entry.getKey(),entry.getValue().get(0)); + mResponse.put("readyState", 2); + mResponse.put("status", statusCode); + + Map simpleHeaders = new HashMap<>(); + if (headers != null) { + Iterator>> it = headers.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> entry = it.next(); + if (entry.getValue().size() > 0) { + simpleHeaders.put(entry.getKey() == null ? "_" : entry.getKey(), entry.getValue().get(0)); + } + } } - mResponse.put("headers",simpleHeaders); + mResponse.put("headers", simpleHeaders); mRespHeaders = simpleHeaders; - if(mProgressCallback!=null){ + if (mProgressCallback != null) { mProgressCallback.invokeAndKeepAlive(mResponse); } } From 24916065ee68bd80e1f45be6d5c3e5f30799eb18 Mon Sep 17 00:00:00 2001 From: sospartan Date: Tue, 28 Feb 2017 15:34:15 +0800 Subject: [PATCH 9/9] * [android] fix domobject NPE --- .../taobao/weex/ui/view/refresh/wrapper/BaseBounceView.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 index e517ab1bd1..1809a78d02 100644 --- 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 @@ -213,6 +213,7 @@ import android.widget.FrameLayout; import com.taobao.weex.common.Constants; +import com.taobao.weex.dom.ImmutableDomObject; import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.ui.view.WXLoadingLayout; import com.taobao.weex.ui.view.WXRefreshLayout; @@ -329,8 +330,9 @@ public void setHeaderView(WXComponent refresh) { public void setFooterView(WXComponent loading) { setLoadmoreEnable(true); if (swipeLayout != null) { - if (swipeLayout.getFooterView() != null) { - swipeLayout.setLoadingHeight((int) loading.getDomObject().getLayoutHeight()); + ImmutableDomObject domObject; + if (swipeLayout.getFooterView() != null && (domObject = loading.getDomObject()) != null) { + swipeLayout.setLoadingHeight((int) domObject.getLayoutHeight()); String colorStr = (String) loading.getDomObject().getStyles().get(Constants.Name.BACKGROUND_COLOR); String bgColor = WXUtils.getString(colorStr, null);