| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.weex; |
| |
| import static org.apache.weex.http.WXHttpUtil.KEY_USER_AGENT; |
| |
| import android.app.Activity; |
| import android.app.AlertDialog; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.graphics.Color; |
| import android.graphics.Paint; |
| import android.net.Uri; |
| import android.support.annotation.NonNull; |
| import android.support.annotation.Nullable; |
| import android.support.annotation.RestrictTo; |
| import android.support.annotation.RestrictTo.Scope; |
| import android.support.annotation.WorkerThread; |
| import android.support.v4.util.ArrayMap; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.view.Menu; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.ScrollView; |
| import com.alibaba.fastjson.JSONObject; |
| import org.apache.weex.adapter.IDrawableLoader; |
| import org.apache.weex.adapter.IWXConfigAdapter; |
| import org.apache.weex.adapter.IWXHttpAdapter; |
| import org.apache.weex.adapter.IWXImgLoaderAdapter; |
| import org.apache.weex.adapter.IWXJscProcessManager; |
| import org.apache.weex.adapter.IWXUserTrackAdapter; |
| import org.apache.weex.adapter.URIAdapter; |
| import org.apache.weex.appfram.websocket.IWebSocketAdapter; |
| import org.apache.weex.bridge.EventResult; |
| import org.apache.weex.bridge.NativeInvokeHelper; |
| import org.apache.weex.bridge.SimpleJSCallback; |
| import org.apache.weex.bridge.WXBridgeManager; |
| import org.apache.weex.bridge.WXModuleManager; |
| import org.apache.weex.bridge.WXParams; |
| import org.apache.weex.common.Constants; |
| import org.apache.weex.common.Destroyable; |
| import org.apache.weex.common.OnWXScrollListener; |
| import org.apache.weex.common.RenderTypes; |
| import org.apache.weex.common.WXConfig; |
| import org.apache.weex.common.WXErrorCode; |
| import org.apache.weex.common.WXModule; |
| import org.apache.weex.common.WXPerformance; |
| import org.apache.weex.common.WXRefreshData; |
| import org.apache.weex.common.WXRenderStrategy; |
| import org.apache.weex.common.WXRequest; |
| import org.apache.weex.dom.WXEvent; |
| import org.apache.weex.http.WXHttpUtil; |
| import org.apache.weex.instance.InstanceOnFireEventInterceptor; |
| import org.apache.weex.jsEngine.JSContext; |
| import org.apache.weex.jsEngine.JSEngine; |
| import org.apache.weex.layout.ContentBoxMeasurement; |
| import org.apache.weex.performance.WXInstanceApm; |
| import org.apache.weex.performance.WXStateRecord; |
| import org.apache.weex.performance.WhiteScreenUtils; |
| import org.apache.weex.render.WXAbstractRenderContainer; |
| import org.apache.weex.tracing.WXTracing; |
| import org.apache.weex.ui.action.GraphicActionAddElement; |
| import org.apache.weex.ui.component.NestedContainer; |
| import org.apache.weex.ui.component.WXComponent; |
| import org.apache.weex.ui.component.WXEmbed; |
| import org.apache.weex.ui.flat.FlatGUIContext; |
| import org.apache.weex.ui.view.WXScrollView; |
| import org.apache.weex.utils.Trace; |
| import org.apache.weex.utils.WXDeviceUtils; |
| import org.apache.weex.utils.WXExceptionUtils; |
| import org.apache.weex.utils.WXFileUtils; |
| import org.apache.weex.utils.WXJsonUtils; |
| import org.apache.weex.utils.WXLogUtils; |
| import org.apache.weex.utils.WXReflectionUtils; |
| import org.apache.weex.utils.WXUtils; |
| import org.apache.weex.utils.WXViewUtils; |
| import org.apache.weex.utils.cache.RegisterCache; |
| import org.apache.weex.utils.tools.LogDetail; |
| import org.apache.weex.utils.tools.TimeCalculator; |
| import java.io.Serializable; |
| import java.lang.ref.WeakReference; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.PriorityQueue; |
| import java.util.concurrent.ConcurrentHashMap; |
| import org.apache.weex.bridge.WXBridgeManager.BundType; |
| |
| |
| /** |
| * Each instance of WXSDKInstance represents an running weex instance. |
| * It can be a pure weex view, or mixed with native view |
| */ |
| public class WXSDKInstance implements IWXActivityStateListener,View.OnLayoutChangeListener { |
| |
| private static final String SOURCE_TEMPLATE_BASE64_MD5 = "templateSourceBase64MD5"; |
| |
| /** |
| * Devtool protocol |
| */ |
| public static String ACTION_DEBUG_INSTANCE_REFRESH = "DEBUG_INSTANCE_REFRESH"; |
| public static String ACTION_INSTANCE_RELOAD = "INSTANCE_RELOAD"; |
| |
| //Performance |
| public boolean mEnd = false; |
| public boolean mHasCreateFinish = false; |
| public static final String BUNDLE_URL = "bundleUrl"; |
| private IWXUserTrackAdapter mUserTrackAdapter; |
| private IWXRenderListener mRenderListener; |
| private IWXStatisticsListener mStatisticsListener; |
| /** package **/ Context mContext; |
| private final String mInstanceId; |
| private WXAbstractRenderContainer mRenderContainer; |
| private WXComponent mRootComp; |
| private boolean mRendered; |
| private WXRefreshData mLastRefreshData; |
| private NestedInstanceInterceptor mNestedInstanceInterceptor; |
| private String mBundleUrl = ""; |
| public static String requestUrl = "requestUrl"; |
| private boolean isDestroy=false; |
| private boolean hasException = false; |
| private boolean isRenderSuccess = false; |
| private boolean createInstanceHeartBeat = false; |
| private Map<String,Serializable> mUserTrackParams; |
| private NativeInvokeHelper mNativeInvokeHelper; |
| private boolean isCommit=false; |
| private WXGlobalEventReceiver mGlobalEventReceiver=null; |
| private boolean trackComponent; |
| private boolean enableLayerType = true; |
| private boolean mNeedValidate = false; |
| private boolean mNeedReLoad = false; |
| private boolean mUseScroller = false; |
| private int mInstanceViewPortWidth = 750; |
| private boolean enableFullScreenHeight = false; |
| private WXInstanceApm mApmForInstance; |
| private @NonNull |
| FlatGUIContext mFlatGUIContext =new FlatGUIContext(); |
| |
| private Map<String,String> mContainerInfo; |
| |
| public boolean isNewFsEnd = false; |
| private List<JSONObject> componentsInfoExceedGPULimit = new LinkedList<>(); |
| |
| /** |
| * bundle type |
| */ |
| public BundType bundleType; |
| public long mRenderStartNanos; |
| public int mExecJSTraceId = WXTracing.nextId(); |
| |
| private boolean isViewDisAppear = false; |
| |
| /** |
| *for network tracker |
| */ |
| public String mwxDims[] = new String [5]; |
| public long measureTimes[] = new long [5]; |
| |
| public WeakReference<String> templateRef; |
| public Map<String,List<String>> responseHeaders = new HashMap<>(); |
| |
| /** |
| * Render strategy. |
| */ |
| private WXRenderStrategy mRenderStrategy = WXRenderStrategy.APPEND_ASYNC; |
| |
| private boolean mDisableSkipFrameworkInit = false; |
| |
| /** |
| * Render start time |
| */ |
| public long mRenderStartTime; |
| /** |
| * Refresh start time |
| */ |
| private long mRefreshStartTime; |
| private WXPerformance mWXPerformance; |
| private ScrollView mScrollView; |
| private WXScrollView.WXScrollViewListener mWXScrollViewListener; |
| |
| private List<OnWXScrollListener> mWXScrollListeners; |
| |
| private List<String> mLayerOverFlowListeners; |
| |
| private List<ActionBarHandler> mWXActionbarHandlers; |
| |
| private List<OnBackPressedHandler> mWXBackPressedHandlers; |
| |
| private List<OnActivityResultHandler> mWXOnActivityResultHandlers; |
| |
| private WXSDKInstance mParentInstance; |
| |
| private String mRenderType = RenderTypes.RENDER_TYPE_NATIVE; |
| |
| private boolean mPageDirty = true; |
| private boolean mFixMultiThreadBug = false; |
| |
| public TimeCalculator mTimeCalculator; |
| /** |
| * Default Width And Viewport is 750, |
| * when screen width change, we adjust viewport to adapter screen change |
| * */ |
| private boolean mAutoAdjustDeviceWidth = WXEnvironment.AUTO_ADJUST_ENV_DEVICE_WIDTH; |
| |
| public List<JSONObject> getComponentsExceedGPULimit(){return componentsInfoExceedGPULimit;} |
| @RestrictTo(Scope.LIBRARY) |
| public void setComponentsInfoExceedGPULimit(JSONObject component){ |
| if(component!= null && !component.isEmpty()){ |
| componentsInfoExceedGPULimit.add(component); |
| } |
| } |
| |
| public List<String> getLayerOverFlowListeners() { |
| return mLayerOverFlowListeners; |
| } |
| |
| public void addLayerOverFlowListener(String ref) { |
| if (mLayerOverFlowListeners == null) |
| mLayerOverFlowListeners = new ArrayList<>(); |
| mLayerOverFlowListeners.add(ref); |
| } |
| |
| public void removeLayerOverFlowListener(String ref) { |
| if (mLayerOverFlowListeners != null) |
| mLayerOverFlowListeners.remove(ref); |
| } |
| |
| /** |
| * whether we are in preRender mode |
| * */ |
| private volatile boolean isPreRenderMode; |
| |
| private boolean mCurrentGround = false; |
| private ComponentObserver mComponentObserver; |
| private Map<String, GraphicActionAddElement> inactiveAddElementAction = new ArrayMap<>(); |
| |
| private Map<Long, ContentBoxMeasurement> mContentBoxMeasurements = new ArrayMap<>(); |
| |
| private List<InstanceOnFireEventInterceptor> mInstanceOnFireEventInterceptorList; |
| |
| |
| /** |
| * network handler |
| */ |
| public interface ImageNetworkHandler { |
| public String fetchLocal(String url); |
| } |
| |
| public interface StreamNetworkHandler { |
| public String fetchLocal(String url); |
| } |
| |
| public interface CustomFontNetworkHandler { |
| public String fetchLocal(String url); |
| } |
| |
| private ImageNetworkHandler mImageNetworkHandler; |
| |
| private StreamNetworkHandler mStreamNetworkHandler; |
| |
| private CustomFontNetworkHandler mCustomFontNetworkHandler; |
| |
| public ImageNetworkHandler getImageNetworkHandler() { |
| return mImageNetworkHandler; |
| } |
| |
| public void setImageNetworkHandler(ImageNetworkHandler imageNetworkHandler) { |
| this.mImageNetworkHandler = imageNetworkHandler; |
| } |
| |
| public StreamNetworkHandler getStreamNetworkHandler() { |
| return mStreamNetworkHandler; |
| } |
| |
| public void setStreamNetworkHandler(StreamNetworkHandler streamNetworkHandler) { |
| this.mStreamNetworkHandler = streamNetworkHandler; |
| } |
| |
| public CustomFontNetworkHandler getCustomFontNetworkHandler() { |
| return mCustomFontNetworkHandler; |
| } |
| |
| public void setCustomFontNetworkHandler(CustomFontNetworkHandler customFontNetworkHandler) { |
| this.mCustomFontNetworkHandler = customFontNetworkHandler; |
| } |
| |
| |
| /** |
| * ActionBar Handler |
| */ |
| |
| public interface ActionBarHandler { |
| boolean onSupportNavigateUp(); |
| } |
| |
| public interface OnBackPressedHandler { |
| boolean onBackPressed(); |
| } |
| |
| public static abstract class OnActivityResultHandler { |
| private String id; |
| |
| public OnActivityResultHandler(String id) { |
| this.id = id; |
| } |
| |
| public abstract boolean onActivityResult(int requestCode, int resultCode, Intent data, String id); |
| |
| public boolean onActivityResult(int requestCode, int resultCode, Intent data) { |
| return onActivityResult(requestCode, resultCode, data, id); |
| } |
| } |
| |
| /** |
| * set make weexCore run in single process mode |
| * @param flag true means weexCore run in single process mode or multi process mode |
| */ |
| public void setUseSingleProcess(boolean flag) { |
| WXBridgeManager.getInstance().setUseSingleProcess(flag); |
| } |
| |
| /** |
| * set open SandBox |
| * @param flag |
| */ |
| public void setUseSandBox(boolean flag) { |
| WXBridgeManager.getInstance().setSandBoxContext(flag); |
| } |
| |
| public PriorityQueue<WXEmbed> hiddenEmbeds; |
| |
| private int maxHiddenEmbedsNum = -1; //max hidden embed num, -1 standard for ulimit |
| |
| public int getMaxHiddenEmbedsNum() { |
| return maxHiddenEmbedsNum; |
| } |
| |
| public void setMaxHiddenEmbedsNum(int maxHiddenEmbedsNum) { |
| this.maxHiddenEmbedsNum = maxHiddenEmbedsNum; |
| } |
| |
| @WorkerThread |
| @RestrictTo(Scope.LIBRARY) |
| public void addInActiveAddElementAction(String ref, GraphicActionAddElement action){ |
| inactiveAddElementAction.put(ref, action); |
| } |
| |
| @WorkerThread |
| @RestrictTo(Scope.LIBRARY) |
| public void removeInActiveAddElmentAction(String ref){ |
| inactiveAddElementAction.remove(ref); |
| } |
| |
| @WorkerThread |
| @RestrictTo(Scope.LIBRARY) |
| public GraphicActionAddElement getInActiveAddElementAction(String ref){ |
| return inactiveAddElementAction.get(ref); |
| } |
| |
| /** |
| * If anchor is created manually(etc. define a layout xml resource ), |
| * be aware do not add it to twice when {@link IWXRenderListener#onViewCreated(WXSDKInstance, View)}. |
| * @param a |
| */ |
| public void setRenderContainer(RenderContainer a){ |
| setWXAbstractRenderContainer(a); |
| } |
| |
| public void setWXAbstractRenderContainer(WXAbstractRenderContainer a){ |
| if(a != null) { |
| a.setSDKInstance(this); |
| a.addOnLayoutChangeListener(this); |
| } |
| |
| mRenderContainer = a; |
| if (mRenderContainer != null && mRenderContainer.getLayoutParams() != null |
| && mRenderContainer.getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) { |
| WXBridgeManager.getInstance().post(new Runnable() { |
| @Override |
| public void run() { |
| WXBridgeManager.getInstance().setRenderContentWrapContentToCore(true, getInstanceId()); |
| } |
| }); |
| } else { |
| WXBridgeManager.getInstance().post(new Runnable() { |
| @Override |
| public void run() { |
| WXBridgeManager.getInstance().setRenderContentWrapContentToCore(false, getInstanceId()); |
| } |
| }); |
| } |
| } |
| |
| private int mMaxDeepLayer; |
| |
| public boolean isTrackComponent() { |
| return trackComponent; |
| } |
| |
| public void setTrackComponent(boolean trackComponent) { |
| this.trackComponent = trackComponent; |
| } |
| |
| /** |
| * Tell whether it is enabled to change the layerType |
| * {@link android.view.View#setLayerType(int, Paint)} |
| * @return True for enable to change the layerType of component, false otherwise. The default |
| * is True |
| */ |
| public boolean isLayerTypeEnabled() { |
| return enableLayerType; |
| } |
| |
| /** |
| * Enable the ability of changing layerType. e.g. {@link android.view.View#setLayerType(int, Paint)} |
| * Disable the ability of changing layerType will have tremendous <strong>performance |
| * punishment</strong>. |
| * |
| * <strong>Do not</strong> set this to false unless you know exactly what you are doing. |
| * @param enable True for enable to change the layerType of component, false otherwise. The default |
| * is True |
| */ |
| public void enableLayerType(boolean enable) { |
| enableLayerType = enable; |
| } |
| |
| @RestrictTo(RestrictTo.Scope.LIBRARY) |
| public @NonNull |
| FlatGUIContext getFlatUIContext(){ |
| return mFlatGUIContext; |
| } |
| |
| public boolean isNeedValidate() { |
| return mNeedValidate; |
| } |
| |
| public boolean isNeedReLoad() { |
| return mNeedReLoad; |
| } |
| |
| public void setNeedLoad(boolean load) { |
| mNeedReLoad = load; |
| } |
| |
| @RestrictTo(Scope.LIBRARY) |
| public void setEnableFullScreenHeight(boolean fullScreenHeight){enableFullScreenHeight = fullScreenHeight;} |
| |
| @RestrictTo(Scope.LIBRARY) |
| public boolean isFullScreenHeightEnabled(){return enableFullScreenHeight;} |
| |
| public boolean isUseScroller() { |
| return mUseScroller; |
| } |
| |
| public void setUseScroller(boolean use) { |
| mUseScroller = use; |
| } |
| |
| public void setInstanceViewPortWidth(int instanceViewPortWidth) { |
| setInstanceViewPortWidth(instanceViewPortWidth,false); |
| |
| } |
| public void setInstanceViewPortWidth(int instanceViewPortWidth,boolean fromMetaModule){ |
| this.mInstanceViewPortWidth = instanceViewPortWidth; |
| this.mAutoAdjustDeviceWidth = false; |
| if(!fromMetaModule){ |
| WXBridgeManager.getInstance().setViewPortWidth(getInstanceId(), mInstanceViewPortWidth); |
| } |
| } |
| public void resetDeviceDisplayOfPage(){ |
| WXBridgeManager.getInstance().setDeviceDisplayOfPage(getInstanceId(), WXViewUtils.getScreenWidth(getContext()), WXViewUtils.getScreenHeight(getContext())); |
| } |
| public void setPageKeepRawCssStyles(){ |
| WXBridgeManager.getInstance().setPageArgument(getInstanceId(),"reserveCssStyles","true"); |
| } |
| public void reloadPageLayout(){ |
| WXBridgeManager.getInstance().reloadPageLayout(getInstanceId()); |
| } |
| |
| public void setAutoAdjustDeviceWidth(boolean autoAdjustViewPort){ |
| this.mAutoAdjustDeviceWidth = autoAdjustViewPort; |
| } |
| |
| public boolean isAutoAdjustDeviceWidth(){ |
| return mAutoAdjustDeviceWidth; |
| } |
| |
| private void setDeviceDisplay(float deviceWith, float deviceHeight, float scale){ |
| WXBridgeManager.getInstance().setDeviceDisplay(getInstanceId(), deviceWith, deviceHeight, scale); |
| } |
| |
| |
| |
| public int getInstanceViewPortWidth(){ |
| return mInstanceViewPortWidth; |
| } |
| |
| public interface OnInstanceVisibleListener{ |
| void onAppear(); |
| void onDisappear(); |
| } |
| private List<OnInstanceVisibleListener> mVisibleListeners = new ArrayList<>(); |
| |
| public WXSDKInstance(Context context) { |
| mInstanceId = WXSDKManager.getInstance().generateInstanceId(); |
| init(context); |
| } |
| |
| //for preInit |
| public WXSDKInstance(){ |
| mInstanceId = WXSDKManager.getInstance().generateInstanceId(); |
| mWXPerformance = new WXPerformance(mInstanceId); |
| mApmForInstance = new WXInstanceApm(mInstanceId); |
| WXSDKManager.getInstance().getAllInstanceMap().put(mInstanceId,this); |
| mTimeCalculator = new TimeCalculator(this); |
| initFixMultiThreadFlag(); |
| } |
| |
| |
| private void initFixMultiThreadFlag() { |
| IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter(); |
| if (adapter != null) { |
| String config = adapter.getConfig("android_weex_ext_config", "fixMultiThreadBug", "true"); |
| mFixMultiThreadBug = Boolean.parseBoolean(config); |
| } |
| } |
| |
| /** |
| * For unittest only. |
| */ |
| @RestrictTo(Scope.TESTS) |
| WXSDKInstance(Context context,String id) { |
| mInstanceId = id; |
| init(context); |
| } |
| |
| public WXComponent getRootComponent() { |
| return mRootComp; |
| } |
| |
| public void setNestedInstanceInterceptor(NestedInstanceInterceptor interceptor){ |
| mNestedInstanceInterceptor = interceptor; |
| } |
| |
| public final WXSDKInstance createNestedInstance(NestedContainer container){ |
| WXSDKInstance sdkInstance = newNestedInstance(); |
| if(mNestedInstanceInterceptor != null){ |
| mNestedInstanceInterceptor.onCreateNestInstance(sdkInstance,container); |
| } |
| if(sdkInstance != null){ |
| sdkInstance.setComponentObserver(this.getComponentObserver()); |
| } |
| return sdkInstance; |
| } |
| |
| protected WXSDKInstance newNestedInstance() { |
| return new WXSDKInstance(mContext); |
| } |
| public boolean isHasException() { |
| return hasException; |
| } |
| |
| public void setHasException(boolean hasException) { |
| this.hasException = hasException; |
| } |
| |
| public void createInstanceFuncHeartBeat() { |
| WXLogUtils.d("createInstanceFuncHeartBeat: " + mInstanceId); |
| this.createInstanceHeartBeat = true; |
| getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_END_EXCUTE_BUNDLE); |
| } |
| |
| public void addOnInstanceVisibleListener(OnInstanceVisibleListener l){ |
| mVisibleListeners.add(l); |
| } |
| |
| public void removeOnInstanceVisibleListener(OnInstanceVisibleListener l){ |
| mVisibleListeners.remove(l); |
| } |
| |
| public void init(Context context) { |
| initFixMultiThreadFlag(); |
| RegisterCache.getInstance().idle(true); |
| mContext = context; |
| mContainerInfo = new HashMap<>(4); |
| mNativeInvokeHelper = new NativeInvokeHelper(mInstanceId); |
| |
| if (null == mWXPerformance){ |
| mWXPerformance = new WXPerformance(mInstanceId); |
| } |
| if (null == mApmForInstance){ |
| mApmForInstance = new WXInstanceApm(mInstanceId); |
| } |
| |
| mWXPerformance.WXSDKVersion = WXEnvironment.WXSDK_VERSION; |
| mWXPerformance.JSLibInitTime = WXEnvironment.sJSLibInitTime; |
| |
| mUserTrackAdapter=WXSDKManager.getInstance().getIWXUserTrackAdapter(); |
| |
| WXSDKManager.getInstance().getAllInstanceMap().put(mInstanceId,this); |
| |
| mContainerInfo.put(WXInstanceApm.KEY_PAGE_PROPERTIES_CONTAINER_NAME, context instanceof Activity |
| ? context.getClass().getSimpleName() |
| :"unKnowContainer" |
| ); |
| mContainerInfo.put(WXInstanceApm.KEY_PAGE_PROPERTIES_INSTANCE_TYPE,"page"); |
| |
| // WXBridgeManager.getInstance().checkJsEngineMultiThread(); |
| mDisableSkipFrameworkInit = isDisableSkipFrameworkInDataRender(); |
| |
| if(mTimeCalculator == null) { |
| mTimeCalculator = new TimeCalculator(this); |
| } |
| } |
| |
| /** |
| * Set a Observer for component. |
| * This observer will be called in each component, should not doing |
| * anything will impact render performance. |
| * |
| * @param observer |
| */ |
| public void setComponentObserver(ComponentObserver observer){ |
| mComponentObserver = observer; |
| } |
| |
| public ComponentObserver getComponentObserver(){ |
| return mComponentObserver; |
| } |
| |
| public NativeInvokeHelper getNativeInvokeHelper() { |
| return mNativeInvokeHelper; |
| } |
| |
| @Deprecated |
| public void setBizType(String bizType) { |
| if (!TextUtils.isEmpty(bizType)) { |
| mWXPerformance.bizType = bizType; |
| } |
| } |
| |
| public ScrollView getScrollView() { |
| return mScrollView; |
| } |
| |
| public void setRootScrollView(ScrollView scrollView) { |
| mScrollView = scrollView; |
| if (mWXScrollViewListener != null && mScrollView instanceof WXScrollView) { |
| ((WXScrollView) mScrollView).addScrollViewListener(mWXScrollViewListener); |
| } |
| } |
| |
| @Deprecated |
| public void registerScrollViewListener(WXScrollView.WXScrollViewListener scrollViewListener) { |
| mWXScrollViewListener = scrollViewListener; |
| } |
| |
| @Deprecated |
| public WXScrollView.WXScrollViewListener getScrollViewListener() { |
| return mWXScrollViewListener; |
| } |
| |
| @Deprecated |
| public void setIWXUserTrackAdapter(IWXUserTrackAdapter adapter) { |
| } |
| |
| public void setContainerInfo(String key,String val){ |
| mContainerInfo.put(key,val); |
| } |
| |
| public Map<String, String> getContainerInfo() { |
| return mContainerInfo; |
| } |
| |
| /** |
| * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy |
| * @param template bundle js |
| * @param options os iphone/android/ipad |
| * weexversion Weex version(like 1.0.0) |
| * appversion App version(like 1.0.0) |
| * devid Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH) |
| * sysversion Device system version(like 5.4.4、7.0.4, should be used with os) |
| * sysmodel Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE") |
| * Time UNIX timestamp, UTC+08:00 |
| * TTID(Optional) |
| * MarkertId |
| * Appname(Optional) tm,tb,qa |
| * Bundleurl(Optional) template url |
| * @param jsonInitData Initial data for rendering |
| */ |
| public void render(String template, Map<String, Object> options, String jsonInitData) { |
| render(template, options, jsonInitData, WXRenderStrategy.APPEND_ASYNC); |
| } |
| |
| /** |
| * Render template asynchronously |
| * @param template bundle js |
| * @param options os iphone/android/ipad |
| * weexversion Weex version(like 1.0.0) |
| * appversion App version(like 1.0.0) |
| * devid Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH) |
| * sysversion Device system version(like 5.4.4、7.0.4, should be used with os) |
| * sysmodel Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE") |
| * Time UNIX timestamp, UTC+08:00 |
| * TTID(Optional) |
| * MarkertId |
| * Appname(Optional) tm,tb,qa |
| * Bundleurl(Optional) template url |
| * @param jsonInitData Initial data for rendering |
| * @param flag RenderStrategy {@link WXRenderStrategy} |
| */ |
| @Deprecated |
| public void render(String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) { |
| render(WXPerformance.DEFAULT, template, options, jsonInitData, flag); |
| } |
| |
| /** |
| * Render template asynchronously |
| * |
| * @param pageName, used for performance log. |
| * @param template bundle js |
| * @param options os iphone/android/ipad |
| * weexversion Weex version(like 1.0.0) |
| * appversion App version(like 1.0.0) |
| * devid Device id(like Aqh9z8dRJNBhmS9drLG5BKCmXhecHUXIZoXOctKwFebH) |
| * sysversion Device system version(like 5.4.4、7.0.4, should be used with os) |
| * sysmodel Device model(like iOS:"MGA82J/A", android:"MI NOTE LTE") |
| * Time UNIX timestamp, UTC+08:00 |
| * TTID(Optional) |
| * MarkertId |
| * Appname(Optional) tm,tb,qa |
| * Bundleurl(Optional) template url |
| * @param jsonInitData Initial data for rendering |
| * @param flag RenderStrategy {@link WXRenderStrategy} |
| */ |
| public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) { |
| render(pageName, new Script(template), options, jsonInitData, flag); |
| } |
| |
| public void render(String pageName, Script template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag) { |
| mWXPerformance.beforeInstanceRender(mInstanceId); |
| |
| if(WXEnvironment.isApkDebugable() && WXPerformance.DEFAULT.equals(pageName)){ |
| |
| if (getUIContext() != null) { |
| new AlertDialog.Builder(getUIContext()) |
| .setTitle("Error: Missing pageName") |
| .setMessage("We highly recommend you to set pageName. Call" + |
| "\nWXSDKInstance#render(String pageName, String template, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag)\n" + |
| "to fix it.") |
| .show(); |
| } |
| |
| return; |
| } |
| renderInternal(pageName,template,options,jsonInitData,flag); |
| } |
| |
| /** |
| * Render binary template asynchronously in DATA_RENDER_BINARY strategy. |
| */ |
| public void render(String pageName, byte[] template, Map<String, Object> options, String jsonInitData) { |
| render(pageName, new Script(template), options, jsonInitData, WXRenderStrategy.DATA_RENDER_BINARY); |
| } |
| |
| private void ensureRenderArchor(){ |
| if(mRenderContainer == null){ |
| if (getContext() != null) { |
| setRenderContainer(new RenderContainer(getContext())); |
| mRenderContainer.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); |
| mRenderContainer.setBackgroundColor(Color.TRANSPARENT); |
| mRenderContainer.setSDKInstance(this); |
| mRenderContainer.addOnLayoutChangeListener(this); |
| } |
| } |
| } |
| |
| private void renderInternal(String pageName, |
| String template, |
| Map<String, Object> options, |
| String jsonInitData, |
| WXRenderStrategy flag) { |
| if (mRendered || TextUtils.isEmpty(template)) { |
| return; |
| } |
| renderInternal(pageName, new Script(template), options, jsonInitData, flag); |
| } |
| |
| private boolean isPreInit = false; |
| public boolean isPreInitMode(){ |
| return isPreInit; |
| } |
| |
| private boolean isPreDownLoad =false; |
| public boolean isPreDownLoad(){ |
| return isPreDownLoad; |
| } |
| |
| public void onInstanceReady(){ |
| WXLogUtils.d("test->","onInstanceReady"); |
| mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_CONTAINER_READY); |
| if (!isPreInit && !isPreDownLoad){ |
| return; |
| } |
| mApmForInstance.onInstanceReady(isPreDownLoad); |
| if (isPreDownLoad){ |
| mHttpListener.onInstanceReady(); |
| } |
| } |
| |
| public void preInit(String pageName, |
| String script, |
| Map<String, Object> options, |
| String jsonInitData, |
| WXRenderStrategy flag){ |
| isPreInit = true; |
| mRenderStrategy = flag; |
| Map<String, Object> renderOptions = options; |
| if (renderOptions == null) { |
| renderOptions = new HashMap<>(); |
| } |
| //mApmForInstance.doInit(); |
| mApmForInstance.isReady = false; |
| WXSDKManager.getInstance().createInstance(this, new Script(script), renderOptions, jsonInitData); |
| } |
| |
| public void preDownLoad(String url, |
| Map<String, Object> options, |
| String jsonInitData, |
| WXRenderStrategy flag){ |
| this.isPreDownLoad =true; |
| mRenderStrategy = flag; |
| mApmForInstance.isReady = false; |
| renderByUrl(url,url,options,jsonInitData,flag); |
| } |
| |
| |
| private void renderInternal(String pageName, |
| Script template, |
| Map<String, Object> options, |
| String jsonInitData, |
| WXRenderStrategy flag){ |
| if (mRendered || template == null || template.isEmpty()) { |
| return; |
| } |
| |
| LogDetail logDetail = mTimeCalculator.createLogDetail("renderInternal"); |
| mRenderStrategy = flag; |
| |
| //some case ,from render(template),but not render (url) |
| if (!mApmForInstance.hasInit()){ |
| mApmForInstance.doInit(); |
| } |
| mApmForInstance.setPageName(pageName); |
| mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_RENDER_ORGIGIN); |
| mApmForInstance.doDelayCollectData(); |
| |
| mWXPerformance.pageName = (TextUtils.isEmpty(pageName) ? "defaultBundleUrl":pageName); |
| if (TextUtils.isEmpty(mBundleUrl)) { |
| mBundleUrl = mWXPerformance.pageName; |
| } |
| |
| if (WXTracing.isAvailable()) { |
| WXTracing.TraceEvent traceEvent = WXTracing.newEvent("executeBundleJS", mInstanceId, -1); |
| traceEvent.traceId = mExecJSTraceId; |
| traceEvent.iid = mInstanceId; |
| traceEvent.tname = "JSThread"; |
| traceEvent.ph = "B"; |
| traceEvent.submit(); |
| mRenderStartNanos = System.nanoTime(); |
| } |
| |
| ensureRenderArchor(); |
| |
| Map<String, Object> renderOptions = options; |
| if (renderOptions == null) { |
| renderOptions = new HashMap<>(); |
| } |
| |
| if (WXEnvironment.sDynamicMode && !TextUtils.isEmpty(WXEnvironment.sDynamicUrl) && renderOptions.get("dynamicMode") == null) { |
| renderOptions.put("dynamicMode", "true"); |
| renderByUrl(pageName, WXEnvironment.sDynamicUrl, renderOptions, jsonInitData, flag); |
| return; |
| } |
| |
| TimeCalculator timeCalculator = new TimeCalculator(this); |
| |
| mWXPerformance.JSTemplateSize = template.length() / 1024f; |
| mApmForInstance.addStats(WXInstanceApm.KEY_PAGE_STATS_BUNDLE_SIZE,mWXPerformance.JSTemplateSize); |
| mRenderStartTime = System.currentTimeMillis(); |
| WXSDKManager.getInstance().setCrashInfo(WXEnvironment.WEEX_CURRENT_KEY,pageName); |
| if(mAutoAdjustDeviceWidth && WXDeviceUtils.isAutoResize(mContext)){ |
| if(WXEnvironment.AUTO_UPDATE_APPLICATION_SCREEN_SIZE) { |
| WXViewUtils.updateApplicationScreen(mContext); |
| } |
| WXParams params = WXBridgeManager.getInstance().getInitParams(); |
| if(params != null && !TextUtils.equals(params.getDeviceWidth(), String.valueOf(WXViewUtils.getScreenWidth(mContext)))){ |
| params.setDeviceWidth(String.valueOf(WXViewUtils.getScreenWidth(mContext))); |
| params.setDeviceHeight(String.valueOf(WXViewUtils.getScreenHeight(mContext))); |
| float density = WXEnvironment.sApplication.getResources().getDisplayMetrics().density; |
| WXEnvironment.addCustomOptions(WXConfig.scale, Float.toString(density)); |
| String statusBarHeight = null; |
| if(WXViewUtils.getStatusBarHeight(mContext) > 0 ){ |
| statusBarHeight = String.valueOf(WXViewUtils.getStatusBarHeight(mContext)); |
| } |
| WXBridgeManager.getInstance().updateInitDeviceParams(params.getDeviceWidth(), |
| params.getDeviceHeight(), |
| Float.toString(density), statusBarHeight); |
| setDeviceDisplay(WXViewUtils.getScreenWidth(mContext), |
| WXViewUtils.getScreenHeight(mContext), |
| WXViewUtils.getScreenDensity(mContext)); |
| } |
| } |
| logDetail.taskStart(); |
| if (isPreInitMode()){ |
| getApmForInstance().onStage(WXInstanceApm.KEY_PAGE_STAGES_LOAD_BUNDLE_START); |
| WXBridgeManager.getInstance().loadJsBundleInPreInitMode(getInstanceId(),template.getContent()); |
| } else { |
| WXSDKManager.getInstance().createInstance(this, template, renderOptions, jsonInitData); |
| } |
| logDetail.taskEnd(); |
| mRendered = true; |
| |
| final IWXJscProcessManager wxJscProcessManager = WXSDKManager.getInstance().getWXJscProcessManager(); |
| |
| if(wxJscProcessManager != null && wxJscProcessManager.shouldReboot()) { |
| WXSDKManager.getInstance().postOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| checkWhiteScreen(); |
| if(isDestroy || hasException || isRenderSuccess) { |
| return; |
| } |
| |
| // there is no need to reboot js engine if render by eagle |
| if(isDataRender()) { |
| return; |
| } |
| |
| View containerView = getContainerView(); |
| if(containerView instanceof ViewGroup) { |
| if(0 == ((ViewGroup) containerView).getChildCount()) { |
| if(wxJscProcessManager.withException(WXSDKInstance.this)) { |
| onJSException(String.valueOf(WXErrorCode.WX_ERR_RELOAD_PAGE),"jsc reboot","jsc reboot"); |
| } |
| if(!createInstanceHeartBeat) { |
| WXBridgeManager.getInstance().callReportCrashReloadPage(mInstanceId, null); |
| WXLogUtils.e("callReportCrashReloadPage with jsc reboot"); |
| } |
| } |
| } |
| } |
| }, wxJscProcessManager.rebootTimeout()); |
| } |
| } |
| |
| |
| private void checkWhiteScreen(){ |
| if (isDestroy ||!WhiteScreenUtils.doWhiteScreenCheck()){ |
| return; |
| } |
| |
| boolean isWS = WhiteScreenUtils.isWhiteScreen(this); |
| if (!isWS){ |
| return; |
| } |
| WXErrorCode errorCode = createInstanceHeartBeat?WXErrorCode.WX_ERROR_WHITE_SCREEN:WXErrorCode.WHITE_SCREEN_RESPONSE_TIMEOUT; |
| if (WXBridgeManager.getInstance().isRebootExceedLimit()){ |
| errorCode = WXErrorCode.WHITE_SCREEN_REBOOT_EXCEED_LIMIT; |
| } |
| Map<String,String> args = new HashMap<>(1); |
| String vieTreeMsg = WhiteScreenUtils.takeViewTreeSnapShot(this); |
| args.put("viewTree",null == vieTreeMsg?"null viewTreeMsg":vieTreeMsg); |
| args.put("weexCoreThreadStackTrace",WXBridgeManager.getInstance().getWeexCoreThreadStackTrace()); |
| |
| for (Map.Entry<String,String> entry: WXStateRecord.getInstance().getStateInfo().entrySet()){ |
| args.put(entry.getKey(),entry.getValue()); |
| } |
| WXExceptionUtils.commitCriticalExceptionRT(getInstanceId(),errorCode,"checkEmptyScreen",errorCode.getErrorMsg(),args); |
| } |
| |
| |
| public boolean skipFrameworkInit(){ |
| return isDataRender() && !mDisableSkipFrameworkInit; |
| } |
| |
| private boolean isDataRender() { |
| return getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY || getRenderStrategy() == WXRenderStrategy.DATA_RENDER; |
| } |
| |
| private void renderByUrlInternal(String pageName, |
| final String url, |
| Map<String, Object> options, |
| final String jsonInitData, |
| WXRenderStrategy flag) { |
| |
| |
| LogDetail logDetail = mTimeCalculator.createLogDetail("renderByUrlInternal"); |
| logDetail.taskStart(); |
| ensureRenderArchor(); |
| pageName = wrapPageName(pageName, url); |
| mBundleUrl = url; |
| mRenderStrategy = flag; |
| if(WXSDKManager.getInstance().getValidateProcessor()!=null) { |
| mNeedValidate = WXSDKManager.getInstance().getValidateProcessor().needValidate(mBundleUrl); |
| } |
| |
| Map<String, Object> renderOptions = options; |
| if (renderOptions == null) { |
| renderOptions = new HashMap<>(); |
| } |
| if (!renderOptions.containsKey(BUNDLE_URL)) { |
| renderOptions.put(BUNDLE_URL, url); |
| } |
| |
| getWXPerformance().pageName = pageName; |
| |
| mApmForInstance.doInit(); |
| mApmForInstance.setPageName(pageName); |
| |
| Uri uri = Uri.parse(url); |
| if (uri != null && TextUtils.equals(uri.getScheme(), "file")) { |
| mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START); |
| String template = WXFileUtils.loadFileOrAsset(assembleFilePath(uri), mContext); |
| mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END); |
| render(pageName,template , renderOptions, jsonInitData, flag); |
| return; |
| } |
| |
| boolean is_wlasm = false; |
| if (uri != null && uri.getPath()!=null) { |
| if(uri.getPath().endsWith(".wlasm")){ |
| is_wlasm = true; |
| } |
| } |
| if (is_wlasm){ |
| flag = WXRenderStrategy.DATA_RENDER_BINARY; |
| } |
| |
| IWXHttpAdapter adapter = WXSDKManager.getInstance().getIWXHttpAdapter(); |
| |
| WXRequest wxRequest = new WXRequest(); |
| wxRequest.url = rewriteUri(Uri.parse(url), URIAdapter.BUNDLE).toString(); |
| if(wxRequest != null && !TextUtils.isEmpty(wxRequest.url)){ |
| requestUrl = wxRequest.url; |
| }else { |
| requestUrl = pageName; |
| } |
| |
| if (wxRequest.paramMap == null) { |
| wxRequest.paramMap = new HashMap<String, String>(); |
| } |
| wxRequest.instanceId = getInstanceId(); |
| wxRequest.paramMap.put(KEY_USER_AGENT, WXHttpUtil.assembleUserAgent(mContext,WXEnvironment.getConfig())); |
| wxRequest.paramMap.put("isBundleRequest","true"); |
| mHttpListener = new WXHttpListener(this, pageName, renderOptions, jsonInitData, flag, System.currentTimeMillis()); |
| mHttpListener.isPreDownLoadMode = isPreDownLoad; |
| mHttpListener.setSDKInstance(this); |
| mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START); |
| adapter.sendRequest(wxRequest, (IWXHttpAdapter.OnHttpListener) mHttpListener); |
| logDetail.taskEnd(); |
| } |
| |
| private WXHttpListener mHttpListener = null; |
| |
| /** |
| * Use {@link #render(String, String, Map, String, WXRenderStrategy)} instead. |
| * @param pageName |
| * @param template |
| * @param options |
| * @param jsonInitData |
| * @param width |
| * @param height |
| * @param flag |
| */ |
| @Deprecated |
| public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, int width, int height, WXRenderStrategy flag) { |
| render(pageName,template,options,jsonInitData,flag); |
| } |
| |
| /** |
| * Render template asynchronously, use {@link WXRenderStrategy#APPEND_ASYNC} as render strategy |
| * @param template bundle js |
| */ |
| public void render(String template) { |
| render(WXPerformance.DEFAULT, template, null, null, mRenderStrategy); |
| } |
| |
| /** |
| * Use {@link #render(String)} instead. |
| * @param template |
| * @param width |
| * @param height |
| */ |
| @Deprecated |
| public void render(String template, int width, int height) { |
| render(template); |
| } |
| |
| /** |
| * Use {@link #renderByUrl(String, String, Map, String, WXRenderStrategy)} instead. |
| * @param pageName |
| * @param url |
| * @param options |
| * @param jsonInitData |
| * @param width |
| * @param height |
| * @param flag |
| */ |
| @Deprecated |
| public void renderByUrl(String pageName, final String url, Map<String, Object> options, final String jsonInitData, final int width, final int height, final WXRenderStrategy flag){ |
| renderByUrl(pageName,url,options,jsonInitData,flag); |
| } |
| |
| public void renderByUrl(String pageName, final String url, Map<String, Object> options, final String jsonInitData, final WXRenderStrategy flag) { |
| renderByUrlInternal(pageName,url,options,jsonInitData,flag); |
| } |
| |
| private String wrapPageName(String pageName, String url) { |
| if(TextUtils.equals(pageName, WXPerformance.DEFAULT)){ |
| pageName = url; |
| WXExceptionUtils.degradeUrl = pageName; |
| try { |
| Uri uri=Uri.parse(url); |
| if(uri!=null){ |
| Uri.Builder builder=new Uri.Builder(); |
| builder.scheme(uri.getScheme()); |
| builder.authority(uri.getAuthority()); |
| builder.path(uri.getPath()); |
| pageName=builder.toString(); |
| } |
| } catch (Exception e) { |
| } |
| } |
| return pageName; |
| } |
| |
| private String assembleFilePath(Uri uri) { |
| if(uri!=null && uri.getPath()!=null){ |
| return uri.getPath().replaceFirst("/",""); |
| } |
| return ""; |
| } |
| |
| public void reloadPage(boolean reloadThis) { |
| |
| WXSDKEngine.reload(); |
| |
| if (reloadThis) { |
| if (mContext != null) { |
| Intent intent = new Intent(); |
| intent.setAction(ACTION_INSTANCE_RELOAD); |
| intent.putExtra("url", mBundleUrl); |
| mContext.sendBroadcast(intent); |
| } |
| // mRendered = false; |
| // destroy(); |
| // renderInternal(mPackage, mTemplate, mOptions, mJsonInitData, mFlag); |
| // refreshInstance("{}"); |
| } else { |
| IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter(); |
| if (adapter != null) { |
| boolean degrade = Boolean.parseBoolean(adapter |
| .getConfig("android_weex_ext_config", |
| "degrade_to_h5_if_not_reload", |
| "true")); |
| WXLogUtils.e("degrade : " + degrade); |
| if(degrade) { |
| onJSException(String.valueOf(WXErrorCode.WX_ERR_RELOAD_PAGE.getErrorCode()),"Do not reloadPage", "Do not reloadPage degradeToH5"); |
| WXLogUtils.e("Do not reloadPage degradeToH5"); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Refresh instance asynchronously. |
| * @param data the new data |
| */ |
| public void refreshInstance(Map<String, Object> data) { |
| if (data == null) { |
| return; |
| } |
| refreshInstance(WXJsonUtils.fromObjectToJSONString(data)); |
| } |
| |
| /** |
| * Refresh instance asynchronously. |
| * @param jsonData the new data |
| */ |
| public void refreshInstance(String jsonData) { |
| if (jsonData == null) { |
| return; |
| } |
| mRefreshStartTime = System.currentTimeMillis(); |
| //cancel last refresh message |
| if (mLastRefreshData != null) { |
| mLastRefreshData.isDirty = true; |
| } |
| |
| mLastRefreshData = new WXRefreshData(jsonData, false); |
| |
| WXSDKManager.getInstance().refreshInstance(mInstanceId, mLastRefreshData); |
| } |
| |
| public WXRenderStrategy getRenderStrategy() { |
| return mRenderStrategy; |
| } |
| |
| public Context getUIContext() { |
| return mContext; |
| } |
| |
| public String getInstanceId() { |
| return mInstanceId; |
| } |
| |
| public Context getContext() { |
| return mContext; |
| } |
| |
| public int getWeexHeight() { |
| return mRenderContainer == null ? 0: mRenderContainer.getHeight(); |
| } |
| |
| public int getWeexWidth() { |
| return mRenderContainer == null ? 0: mRenderContainer.getWidth(); |
| } |
| |
| |
| public IWXImgLoaderAdapter getImgLoaderAdapter() { |
| return WXSDKManager.getInstance().getIWXImgLoaderAdapter(); |
| } |
| |
| public IDrawableLoader getDrawableLoader() { |
| return WXSDKManager.getInstance().getDrawableLoader(); |
| } |
| |
| public URIAdapter getURIAdapter(){ |
| return WXSDKManager.getInstance().getURIAdapter(); |
| } |
| |
| public Uri rewriteUri(Uri uri,String type){ |
| return getURIAdapter().rewrite(this,type,uri); |
| } |
| |
| public IWXHttpAdapter getWXHttpAdapter() { |
| return WXSDKManager.getInstance().getIWXHttpAdapter(); |
| } |
| |
| public IWXStatisticsListener getWXStatisticsListener() { |
| return mStatisticsListener; |
| } |
| |
| public @Nullable |
| IWebSocketAdapter getWXWebSocketAdapter() { |
| return WXSDKManager.getInstance().getIWXWebSocketAdapter(); |
| } |
| |
| @Deprecated |
| public void reloadImages() { |
| if (mScrollView == null) { |
| return; |
| } |
| } |
| |
| |
| public boolean isPreRenderMode() { |
| return this.isPreRenderMode; |
| } |
| |
| public void setPreRenderMode(final boolean isPreRenderMode) { |
| WXSDKManager.getInstance().getWXRenderManager().postOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| WXSDKInstance.this.isPreRenderMode = isPreRenderMode; |
| } |
| },0); |
| } |
| |
| public void setContext(@NonNull Context context) { |
| this.mContext = context; |
| } |
| |
| /******************************** |
| * begin register listener |
| ********************************************************/ |
| public void registerRenderListener(IWXRenderListener listener) { |
| mRenderListener = listener; |
| } |
| |
| @Deprecated |
| public void registerActivityStateListener(IWXActivityStateListener listener) { |
| |
| } |
| |
| public void registerStatisticsListener(IWXStatisticsListener listener) { |
| mStatisticsListener = listener; |
| } |
| |
| /**set render start time*/ |
| public void setRenderStartTime(long renderStartTime) { |
| this.mRenderStartTime = renderStartTime; |
| } |
| |
| /******************************** |
| * end register listener |
| ********************************************************/ |
| |
| |
| /******************************** |
| * begin hook Activity life cycle callback |
| ********************************************************/ |
| |
| @Override |
| public void onActivityCreate() { |
| |
| // module listen Activity onActivityCreate |
| WXModuleManager.onActivityCreate(getInstanceId()); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityCreate(); |
| }else{ |
| if (WXEnvironment.isApkDebugable()){ |
| WXLogUtils.w("Warning :Component tree has not build completely,onActivityCreate can not be call!"); |
| } |
| } |
| |
| mGlobalEventReceiver=new WXGlobalEventReceiver(this); |
| try { |
| getContext().registerReceiver(mGlobalEventReceiver, new IntentFilter(WXGlobalEventReceiver.EVENT_ACTION)); |
| } catch (Throwable e) { |
| // Huawei may throw a exception if register more than 500 BroadcastReceivers |
| WXLogUtils.e(e.getMessage()); |
| mGlobalEventReceiver = null; |
| } |
| |
| } |
| |
| @Override |
| public void onActivityStart() { |
| |
| // module listen Activity onActivityCreate |
| WXModuleManager.onActivityStart(getInstanceId()); |
| if(mRootComp != null) { |
| mRootComp.onActivityStart(); |
| }else{ |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.w("Warning :Component tree has not build completely,onActivityStart can not be call!"); |
| |
| } |
| } |
| |
| } |
| |
| public boolean onCreateOptionsMenu(Menu menu) { |
| |
| WXModuleManager.onCreateOptionsMenu(getInstanceId(),menu); |
| if(mRootComp != null) { |
| mRootComp.onCreateOptionsMenu(menu); |
| }else{ |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.w("Warning :Component tree has not build completely,onActivityStart can not be call!"); |
| |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public void onActivityPause() { |
| onViewDisappear(); |
| if(!isCommit){ |
| if(mUseScroller){ |
| mWXPerformance.useScroller=1; |
| } |
| mWXPerformance.maxDeepViewLayer=getMaxDeepLayer(); |
| mWXPerformance.wxDims = mwxDims; |
| mWXPerformance.measureTimes = measureTimes; |
| if (mUserTrackAdapter != null) { |
| mUserTrackAdapter.commit(mContext, null, IWXUserTrackAdapter.LOAD, mWXPerformance, getUserTrackParams()); |
| } |
| isCommit=true; |
| } |
| // module listen Activity onActivityPause |
| WXModuleManager.onActivityPause(getInstanceId()); |
| if(mRootComp != null) { |
| mRootComp.onActivityPause(); |
| }else{ |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.w("Warning :Component tree has not build completely,onActivityPause can not be call!"); |
| } |
| } |
| |
| if (!mCurrentGround) { |
| WXLogUtils.i("Application to be in the backround"); |
| Intent intent = new Intent(WXGlobalEventReceiver.EVENT_ACTION); |
| intent.putExtra(WXGlobalEventReceiver.EVENT_NAME, Constants.Event.PAUSE_EVENT); |
| intent.putExtra(WXGlobalEventReceiver.EVENT_WX_INSTANCEID, getInstanceId()); |
| /** |
| * Fix NPE just like {@link #onActivityResume()} |
| */ |
| if (null != mContext){ |
| mContext.sendBroadcast(intent); |
| }else { |
| try { |
| WXEnvironment.getApplication().sendBroadcast(intent); |
| } catch (Exception e){ |
| WXLogUtils.e("weex",e); |
| } |
| } |
| this.mCurrentGround = true; |
| } |
| |
| //component appear |
| if((WXEnvironment.isApkDebugable() || WXEnvironment.isPerf()) && mApmForInstance != null){ |
| WXLogUtils.e("PerformanceData " + mApmForInstance.toPerfString()); |
| } |
| } |
| |
| |
| @Override |
| public void onActivityResume() { |
| |
| // notify onActivityResume callback to module |
| WXModuleManager.onActivityResume(getInstanceId()); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityResume(); |
| }else{ |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityResume can not be call!"); |
| } |
| } |
| |
| if (mCurrentGround) { |
| WXLogUtils.i("Application to be in the foreground"); |
| Intent intent = new Intent(WXGlobalEventReceiver.EVENT_ACTION); |
| intent.putExtra(WXGlobalEventReceiver.EVENT_NAME, Constants.Event.RESUME_EVENT); |
| intent.putExtra(WXGlobalEventReceiver.EVENT_WX_INSTANCEID, getInstanceId()); |
| //todo tmp solution for gray version |
| if (null != mContext){ |
| mContext.sendBroadcast(intent); |
| }else { |
| WXEnvironment.getApplication().sendBroadcast(intent); |
| } |
| this.mCurrentGround = false; |
| } |
| |
| onViewAppear(); |
| } |
| |
| @Override |
| public void onActivityStop() { |
| |
| // notify onActivityResume callback to module |
| WXModuleManager.onActivityStop(getInstanceId()); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityStop(); |
| }else{ |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityStop can not be call!"); |
| } |
| } |
| |
| } |
| |
| @Override |
| public void onActivityDestroy() { |
| WXModuleManager.onActivityDestroy(getInstanceId()); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityDestroy(); |
| }else{ |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityDestroy can not be call!"); |
| } |
| } |
| this.mTimeCalculator.println(); |
| destroy(); |
| } |
| |
| @Override |
| public boolean onActivityBack() { |
| |
| WXModuleManager.onActivityBack(getInstanceId()); |
| |
| if(mRootComp != null) { |
| return mRootComp.onActivityBack(); |
| }else{ |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityBack can not be call!"); |
| } |
| } |
| |
| return false; |
| } |
| |
| public boolean onSupportNavigateUp() { |
| if (mWXActionbarHandlers != null) { |
| for (ActionBarHandler handler : mWXActionbarHandlers) { |
| if (handler.onSupportNavigateUp()) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| public boolean onBackPressed() { |
| if(mWXBackPressedHandlers != null) { |
| for (OnBackPressedHandler handler : mWXBackPressedHandlers) { |
| if(handler.onBackPressed()) { |
| return true; |
| } |
| } |
| } |
| |
| WXComponent comp = getRootComponent(); |
| if(comp != null) { |
| WXEvent events= comp.getEvents(); |
| boolean hasNativeBackHook = events.contains(Constants.Event.NATIVE_BACK); |
| if (hasNativeBackHook) { |
| EventResult result = comp.fireEventWait(Constants.Event.NATIVE_BACK, null); |
| if (WXUtils.getBoolean(result.getResult(), false)) { |
| return true; |
| } |
| } |
| |
| boolean hasBackPressed = events.contains(Constants.Event.CLICKBACKITEM); |
| if (hasBackPressed) { |
| fireEvent(comp.getRef(), Constants.Event.CLICKBACKITEM,null, null); |
| } |
| return hasBackPressed; |
| } |
| return false; |
| } |
| |
| public void onActivityResult(int requestCode, int resultCode, Intent data){ |
| WXModuleManager.onActivityResult(getInstanceId(),requestCode,resultCode,data); |
| |
| if(mRootComp != null) { |
| mRootComp.onActivityResult(requestCode,resultCode,data); |
| }else{ |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.w("Warning :Component tree has not build completely, onActivityResult can not be call!"); |
| } |
| } |
| |
| |
| if (mWXOnActivityResultHandlers != null && !mWXOnActivityResultHandlers.isEmpty()) { |
| for (OnActivityResultHandler onActivityResultHandler : mWXOnActivityResultHandlers) { |
| if (onActivityResultHandler.onActivityResult(requestCode, resultCode, data)) { |
| break; |
| } |
| } |
| } |
| |
| } |
| |
| |
| public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { |
| |
| WXModuleManager.onRequestPermissionsResult(getInstanceId(),requestCode,permissions,grantResults); |
| |
| if(mRootComp != null) { |
| mRootComp.onRequestPermissionsResult(requestCode,permissions,grantResults); |
| }else{ |
| if (WXEnvironment.isApkDebugable()) { |
| WXLogUtils.w( |
| "Warning :Component tree has not build completely, onRequestPermissionsResult can not be call!"); |
| } |
| } |
| } |
| |
| /******************************** |
| * end hook Activity life cycle callback |
| ********************************************************/ |
| |
| public void onViewDisappear(){ |
| isViewDisAppear = false; |
| mApmForInstance.onDisAppear(); |
| WXComponent comp = getRootComponent(); |
| if(comp != null) { |
| fireEvent(comp.getRef(), Constants.Event.VIEWDISAPPEAR, null, null); |
| //call disappear of nested instances |
| for(OnInstanceVisibleListener instance:mVisibleListeners){ |
| instance.onDisappear(); |
| } |
| } |
| } |
| |
| public boolean isViewDisAppear(){ |
| return isViewDisAppear; |
| } |
| |
| public void onViewAppear(){ |
| isViewDisAppear = true; |
| mApmForInstance.onAppear(); |
| WXComponent comp = getRootComponent(); |
| if(comp != null) { |
| fireEvent( comp.getRef(), Constants.Event.VIEWAPPEAR,null, null); |
| for(OnInstanceVisibleListener instance:mVisibleListeners){ |
| instance.onAppear(); |
| } |
| } |
| } |
| |
| |
| public void onCreateFinish() { |
| if(mHasCreateFinish){ |
| return; |
| } |
| if (mContext != null) { |
| onViewAppear(); |
| View wxView= mRenderContainer; |
| if(mRenderListener != null) { |
| mRenderListener.onViewCreated(WXSDKInstance.this, wxView); |
| } |
| if (mStatisticsListener != null) { |
| mStatisticsListener.onFirstView(); |
| } |
| } |
| } |
| |
| /** |
| * call back when update finish |
| */ |
| public void onUpdateFinish() { |
| if (WXEnvironment.isApkDebugable()){ |
| WXLogUtils.d("Instance onUpdateSuccess"); |
| } |
| } |
| |
| |
| public void runOnUiThread(Runnable action) { |
| WXSDKManager.getInstance().postOnUiThread(action, 0); |
| } |
| |
| public void onRenderSuccess(final int width, final int height) { |
| isRenderSuccess = true; |
| if (!isNewFsEnd){ |
| getApmForInstance().arriveNewFsRenderTime(); |
| } |
| if (!getApmForInstance().stageMap.containsKey(WXInstanceApm.KEY_PAGE_STAGES_INTERACTION)){ |
| getApmForInstance().arriveInteraction(getRootComponent()); |
| } |
| |
| long time = System.currentTimeMillis() - mRenderStartTime; |
| long[] renderFinishTime = WXBridgeManager.getInstance().getRenderFinishTime(getInstanceId()); |
| |
| mWXPerformance.callBridgeTime = renderFinishTime[0]; |
| mWXPerformance.cssLayoutTime = renderFinishTime[1]; |
| mWXPerformance.parseJsonTime = renderFinishTime[2]; |
| |
| mWXPerformance.totalTime = time; |
| if(mWXPerformance.screenRenderTime<0.001){ |
| mWXPerformance.screenRenderTime = time; |
| } |
| |
| if (mRenderListener != null && mContext != null) { |
| mRenderListener.onRenderSuccess(WXSDKInstance.this, width, height); |
| if (mUserTrackAdapter != null) { |
| WXPerformance performance=new WXPerformance(mInstanceId); |
| performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode(); |
| performance.args=getBundleUrl(); |
| mUserTrackAdapter.commit(mContext,null,IWXUserTrackAdapter.JS_BRIDGE,performance,getUserTrackParams()); |
| } |
| if (WXEnvironment.isApkDebugable()){ |
| WXLogUtils.d(WXLogUtils.WEEX_PERF_TAG, mWXPerformance.toString()); |
| } |
| } |
| if(WXEnvironment.isPerf()){ |
| WXLogUtils.e("weex_perf",mWXPerformance.getPerfData()); |
| } |
| } |
| |
| public void onRefreshSuccess(final int width, final int height) { |
| if (mRenderListener != null && mContext != null) { |
| mRenderListener.onRefreshSuccess(WXSDKInstance.this, width, height); |
| } |
| } |
| |
| public void onChangeElement(WXComponent component, boolean isOutOfScreen) { |
| |
| if (isDestroy() || null == mRenderContainer || mWXPerformance == null ){ |
| return; |
| } |
| if (null == component || component.isIgnoreInteraction){ |
| return; |
| } |
| |
| if (mRenderContainer.hasConsumeEvent()) { |
| return; |
| } |
| |
| long lastElementChangeTime = System.currentTimeMillis(); |
| |
| long lazyLoadTime; |
| |
| if (mHasCreateFinish){ |
| lazyLoadTime = lastElementChangeTime - mWXPerformance.renderTimeOrigin; |
| if (lazyLoadTime > 8000) { |
| //force record detail performance data |
| return; |
| } |
| } |
| |
| if (component.mIsAddElementToTree) { |
| getWXPerformance().localInteractionViewAddCount++; |
| if (!isOutOfScreen) |
| getWXPerformance().interactionViewAddLimitCount++; |
| component.mIsAddElementToTree = false; |
| } |
| |
| if (!isOutOfScreen) { |
| mApmForInstance.arriveInteraction(component); |
| } |
| } |
| |
| public void onRenderError(final String errCode, final String msg) { |
| WXStateRecord.getInstance().recordException(getInstanceId(),"onRenderError,"+errCode+","+msg); |
| if (mRenderListener != null && mContext != null) { |
| WXLogUtils.e("onRenderError "+errCode +","+msg); |
| runOnUiThread(new Runnable() { |
| |
| @Override |
| public void run() { |
| if (mRenderListener != null && mContext != null) { |
| mRenderListener.onException(WXSDKInstance.this, errCode, msg); |
| } |
| } |
| }); |
| } |
| } |
| |
| public void onJSException(final String errCode, final String function, final String exception) { |
| WXStateRecord.getInstance().recordException(getInstanceId(),"onJSException,"+errCode+","+function+"|"+exception); |
| hasException = true; |
| if (mRenderListener != null && mContext != null) { |
| WXLogUtils.e("onJSException "+errCode +","+exception); |
| runOnUiThread(new Runnable() { |
| |
| @Override |
| public void run() { |
| if (mRenderListener != null && mContext != null) { |
| StringBuilder builder = new StringBuilder(); |
| builder.append(function); |
| builder.append(exception); |
| mRenderListener.onException(WXSDKInstance.this, errCode, builder.toString()); |
| } |
| } |
| }); |
| } |
| } |
| |
| |
| @Override |
| public final void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int |
| oldTop, int oldRight, int oldBottom) { |
| if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) { |
| onLayoutChange(v); |
| } |
| } |
| |
| /** |
| * Subclass should override this method to get notifications of layout change of GodView. |
| * @param godView the godView. |
| */ |
| public void onLayoutChange(View godView) { |
| |
| } |
| |
| private boolean mCreateInstance =true; |
| public void firstScreenCreateInstanceTime(long time) { |
| if(mCreateInstance) { |
| mWXPerformance.firstScreenJSFExecuteTime = time -mRenderStartTime; |
| mCreateInstance =false; |
| } |
| } |
| |
| public void callJsTime(final long time){ |
| if (!mEnd){ |
| mWXPerformance.fsCallJsTotalTime+=time; |
| mWXPerformance.fsCallJsTotalNum++; |
| } |
| } |
| |
| public void onComponentCreate(WXComponent component,long createTime) { |
| mWXPerformance.mActionAddElementCount++; |
| mWXPerformance.mActionAddElementSumTime += createTime; |
| if (!mEnd){ |
| mWXPerformance.fsComponentCreateTime+=createTime; |
| mWXPerformance.fsComponentCount++; |
| } |
| mWXPerformance.componentCount++; |
| mWXPerformance.componentCreateTime+=createTime; |
| } |
| |
| public void callActionAddElementTime(long time) { |
| mWXPerformance.mActionAddElementSumTime += time; |
| } |
| |
| public void onOldFsRenderTimeLogic(){ |
| if (mEnd){ |
| return; |
| } |
| mEnd = true; |
| if (mStatisticsListener != null && mContext != null) { |
| runOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| if (mStatisticsListener != null && mContext != null) { |
| Trace.beginSection("onFirstScreen"); |
| mStatisticsListener.onFirstScreen(); |
| Trace.endSection(); |
| } |
| } |
| }); |
| } |
| mApmForInstance.arriveFSRenderTime(); |
| mWXPerformance.fsRenderTime = System.currentTimeMillis(); |
| mWXPerformance.screenRenderTime = System.currentTimeMillis() - mRenderStartTime; |
| } |
| |
| public WXSDKInstance getParentInstance() { |
| return mParentInstance; |
| } |
| |
| public void setParentInstance(WXSDKInstance mParentInstance) { |
| this.mParentInstance = mParentInstance; |
| } |
| |
| private void destroyView(View rootView) { |
| try { |
| if (rootView instanceof ViewGroup) { |
| ViewGroup cViewGroup = ((ViewGroup) rootView); |
| for (int index = 0; index < cViewGroup.getChildCount(); index++) { |
| destroyView(cViewGroup.getChildAt(index)); |
| } |
| |
| cViewGroup.removeViews(0, ((ViewGroup) rootView).getChildCount()); |
| // Ensure that the viewgroup's status to be normal |
| WXReflectionUtils.setValue(rootView, "mChildrenCount", 0); |
| |
| } |
| if(rootView instanceof Destroyable){ |
| ((Destroyable)rootView).destroy(); |
| } |
| } catch (Exception e) { |
| WXLogUtils.e("WXSDKInstance destroyView Exception: ", e); |
| } |
| } |
| |
| public synchronized void destroy() { |
| if(!isDestroy()) { |
| if(mParentInstance != null){ |
| mParentInstance = null; |
| } |
| mApmForInstance.onEnd(); |
| |
| |
| if(mRendered) { |
| WXSDKManager.getInstance().destroyInstance(mInstanceId); |
| } |
| |
| try { |
| if (mGlobalEventReceiver != null) { |
| getContext().unregisterReceiver(mGlobalEventReceiver); |
| mGlobalEventReceiver = null; |
| } |
| }catch (IllegalArgumentException e){ |
| WXLogUtils.w(WXLogUtils.getStackTrace(e)); |
| } |
| |
| if (mRootComp != null) { |
| mRootComp.destroy(); |
| mRootComp = null; |
| } |
| |
| if(mRenderContainer != null){ |
| destroyView(mRenderContainer); |
| } |
| |
| |
| if (mGlobalEvents != null) { |
| mGlobalEvents.clear(); |
| } |
| |
| if (mComponentObserver != null) { |
| mComponentObserver = null; |
| } |
| |
| if (mLayerOverFlowListeners != null) { |
| mLayerOverFlowListeners.clear(); |
| } |
| |
| if(mWXOnActivityResultHandlers != null && !mWXOnActivityResultHandlers.isEmpty()) { |
| mWXOnActivityResultHandlers.clear(); |
| } |
| |
| if(mWXBackPressedHandlers != null && !mWXBackPressedHandlers.isEmpty()) { |
| mWXBackPressedHandlers.clear(); |
| } |
| |
| if(mWXActionbarHandlers != null && !mWXActionbarHandlers.isEmpty()) { |
| mWXActionbarHandlers.clear(); |
| } |
| |
| getFlatUIContext().destroy(); |
| mFlatGUIContext = null; |
| mInstanceOnFireEventInterceptorList = null; |
| mWXScrollListeners = null; |
| mWXActionbarHandlers = null; |
| mWXBackPressedHandlers = null; |
| mRenderContainer = null; |
| mNestedInstanceInterceptor = null; |
| mUserTrackAdapter = null; |
| mScrollView = null; |
| mContext = null; |
| mRenderListener = null; |
| isDestroy = true; |
| mStatisticsListener = null; |
| if(responseHeaders != null){ |
| responseHeaders.clear(); |
| } |
| if(templateRef != null){ |
| templateRef = null; |
| } |
| if (null != mContentBoxMeasurements) { |
| mContentBoxMeasurements.clear(); |
| } |
| mWXPerformance.afterInstanceDestroy(mInstanceId); |
| |
| WXBridgeManager.getInstance().post(new Runnable() { |
| @Override |
| public void run() { |
| WXBridgeManager.getInstance().onInstanceClose(getInstanceId()); |
| inactiveAddElementAction.clear(); |
| } |
| }); |
| |
| //when report error in @WXExceptionUtils |
| // instance may had destroy and remove, |
| // so we delay remove from allInstanceMap |
| WXBridgeManager.getInstance().postDelay(new Runnable() { |
| @Override |
| public void run() { |
| WXSDKManager.getInstance().getAllInstanceMap().remove(mInstanceId); |
| } |
| },1000); |
| } |
| } |
| |
| public boolean isDestroy(){ |
| return isDestroy; |
| } |
| |
| /** |
| * @return If you use render () the return value may be empty |
| */ |
| public @Nullable String getBundleUrl() { |
| return mBundleUrl; |
| } |
| |
| public View getRootView() { |
| if (mRootComp == null) |
| return null; |
| return mRootComp.getRealView(); |
| } |
| |
| public View getContainerView() { |
| return mRenderContainer; |
| } |
| |
| @Deprecated |
| public void setBundleUrl(String url){ |
| mBundleUrl = url; |
| if(WXSDKManager.getInstance().getValidateProcessor()!=null) { |
| mNeedValidate = WXSDKManager.getInstance().getValidateProcessor().needValidate(mBundleUrl); |
| } |
| } |
| |
| public void onRootCreated(WXComponent root) { |
| this.mRootComp = root; |
| this.mRootComp.mDeepInComponentTree =1; |
| mRenderContainer.addView(root.getHostView()); |
| |
| |
| setSize(mRenderContainer.getWidth(),mRenderContainer.getHeight()); |
| } |
| |
| /** |
| * Move fixed view to container ,except it's already moved. |
| * @param fixedChild |
| */ |
| public void moveFixedView(View fixedChild){ |
| if(mRenderContainer != null) { |
| ViewGroup parent; |
| if((parent = (ViewGroup) fixedChild.getParent()) != null){ |
| if (parent != mRenderContainer) { |
| parent.removeView(fixedChild); |
| mRenderContainer.addView(fixedChild); |
| } |
| }else{ |
| mRenderContainer.addView(fixedChild); |
| } |
| } |
| } |
| |
| public void removeFixedView(View fixedChild){ |
| if(mRenderContainer != null) { |
| mRenderContainer.removeView(fixedChild); |
| } |
| } |
| |
| public int getRenderContainerPaddingLeft() { |
| if(mRenderContainer != null) { |
| return mRenderContainer.getPaddingLeft(); |
| } |
| return 0; |
| } |
| |
| public int getRenderContainerPaddingRight() { |
| if(mRenderContainer != null) { |
| return mRenderContainer.getPaddingRight(); |
| } |
| return 0; |
| } |
| |
| public int getRenderContainerPaddingTop() { |
| if(mRenderContainer != null) { |
| return mRenderContainer.getPaddingTop(); |
| } |
| return 0; |
| } |
| |
| public synchronized List<OnWXScrollListener> getWXScrollListeners() { |
| return mWXScrollListeners; |
| } |
| |
| public synchronized void registerOnWXScrollListener(OnWXScrollListener wxScrollListener) { |
| if(mWXScrollListeners==null){ |
| mWXScrollListeners=new ArrayList<>(); |
| } |
| mWXScrollListeners.add(wxScrollListener); |
| } |
| |
| public synchronized void registerActionbarHandler(ActionBarHandler actionBarHandler) { |
| if(actionBarHandler == null) { |
| return; |
| } |
| if(mWXActionbarHandlers == null) { |
| mWXActionbarHandlers = new ArrayList<>(); |
| } |
| |
| mWXActionbarHandlers.add(actionBarHandler); |
| } |
| |
| public synchronized void unRegisterActionbarHandler(ActionBarHandler actionBarHandler) { |
| if(mWXActionbarHandlers != null && actionBarHandler != null) { |
| mWXActionbarHandlers.remove(actionBarHandler); |
| } |
| } |
| |
| public synchronized void unRegisterOnActivityResultHandler(OnActivityResultHandler onActivityResultHandler) { |
| if(mWXOnActivityResultHandlers != null && onActivityResultHandler != null) { |
| mWXOnActivityResultHandlers.remove(onActivityResultHandler); |
| } |
| } |
| |
| public synchronized void registerOnActivityResultHandler(OnActivityResultHandler onActivityResultHandler) { |
| if(onActivityResultHandler == null) { |
| return; |
| } |
| |
| if(mWXOnActivityResultHandlers == null) { |
| mWXOnActivityResultHandlers = new ArrayList<>(); |
| } |
| mWXOnActivityResultHandlers.add(onActivityResultHandler); |
| } |
| |
| |
| public synchronized void registerBackPressedHandler(OnBackPressedHandler backPressedHandler) { |
| if(backPressedHandler == null) { |
| return; |
| } |
| |
| if(mWXBackPressedHandlers == null) { |
| mWXBackPressedHandlers = new ArrayList<>(); |
| } |
| |
| mWXBackPressedHandlers.add(backPressedHandler); |
| } |
| |
| public synchronized void unRegisterBackPressedHandler(OnBackPressedHandler backPressedHandler) { |
| if(mWXBackPressedHandlers != null && backPressedHandler != null) { |
| mWXBackPressedHandlers.remove(backPressedHandler); |
| } |
| } |
| |
| static int sScreenHeight = -1; |
| public void setSize(int width, int height) { |
| if (width > 0 && height > 0 & !isDestroy && mRendered && mRenderContainer != null) { |
| if (sScreenHeight < 0){ |
| sScreenHeight = WXViewUtils.getScreenHeight(getContext()); |
| } |
| if (sScreenHeight>0){ |
| double screenRatio = (double)height/(double)sScreenHeight *100; |
| if(screenRatio>100){ |
| screenRatio =100; |
| } |
| getApmForInstance().addStats(WXInstanceApm.KEY_PAGE_STATS_BODY_RATIO,screenRatio); |
| } |
| ViewGroup.LayoutParams layoutParams = mRenderContainer.getLayoutParams(); |
| if (layoutParams != null) { |
| final float realWidth = width; |
| final float realHeight = height; |
| if (mRenderContainer.getWidth() != width || mRenderContainer.getHeight() != height) { |
| layoutParams.width = width; |
| layoutParams.height = height; |
| mRenderContainer.setLayoutParams(layoutParams); |
| } |
| |
| if (mRootComp != null && layoutParams != null) { |
| final boolean isWidthWrapContent = layoutParams.width == ViewGroup.LayoutParams.WRAP_CONTENT; |
| final boolean isHeightWrapContent = layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT; |
| |
| WXBridgeManager.getInstance().post(new Runnable() { |
| @Override |
| public void run() { |
| WXBridgeManager.getInstance().setDefaultRootSize(getInstanceId(), realWidth, realHeight, isWidthWrapContent, |
| isHeightWrapContent); |
| } |
| }); |
| } |
| } |
| } |
| } |
| |
| /*Global Event*/ |
| private HashMap<String, List<String>> mGlobalEvents = new HashMap<>(); |
| |
| public void fireGlobalEventCallback(String eventName, Map<String,Object> params){ |
| List<String> callbacks=mGlobalEvents.get(eventName); |
| if(callbacks!=null){ |
| for(String callback:callbacks){ |
| WXSDKManager.getInstance().callback(mInstanceId,callback,params,true); |
| } |
| } |
| } |
| |
| /** |
| * Fire event callback on a element. |
| * @param elementRef |
| * @param type |
| * @param data |
| * @param domChanges |
| */ |
| public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges, List<Object> eventArgs){ |
| fireEvent(elementRef, type, data, domChanges, eventArgs, null); |
| } |
| |
| public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges, List<Object> eventArgs, EventResult callback) { |
| onInterceptInstanceEvent(getInstanceId(), elementRef, type, data, domChanges); |
| if (null != mWXPerformance && mWXPerformance.fsCallEventTotalNum<Integer.MAX_VALUE){ |
| mWXPerformance.fsCallEventTotalNum++; |
| } |
| mApmForInstance.updateFSDiffStats(WXInstanceApm.KEY_PAGE_STATS_FS_CALL_EVENT_NUM,1); |
| WXBridgeManager.getInstance().fireEventOnNode(getInstanceId(),elementRef,type,data,domChanges, eventArgs, callback); |
| } |
| |
| |
| /** |
| * Fire event callback on a element. |
| * @param elementRef |
| * @param type |
| * @param data |
| * @param domChanges |
| */ |
| public void fireEvent(String elementRef,final String type, final Map<String, Object> data,final Map<String, Object> domChanges){ |
| fireEvent(elementRef, type, data, domChanges, null); |
| } |
| |
| public void fireEvent(String elementRef,final String type, final Map<String, Object> data){ |
| fireEvent(elementRef,type,data,null); |
| } |
| |
| public void fireEvent(String ref, String type){ |
| fireEvent(ref,type,new HashMap<String, Object>()); |
| } |
| |
| protected void addEventListener(String eventName, String callback) { |
| if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) { |
| return; |
| } |
| List<String> callbacks = mGlobalEvents.get(eventName); |
| if (callbacks == null) { |
| callbacks = new ArrayList<>(); |
| mGlobalEvents.put(eventName, callbacks); |
| } |
| callbacks.add(callback); |
| } |
| protected void removeEventListener(String eventName, String callback) { |
| if (TextUtils.isEmpty(eventName) || TextUtils.isEmpty(callback)) { |
| return; |
| } |
| List<String> callbacks = mGlobalEvents.get(eventName); |
| if (callbacks != null) { |
| callbacks.remove(callback); |
| } |
| } |
| |
| protected void removeEventListener(String eventName) { |
| if (TextUtils.isEmpty(eventName)) { |
| return; |
| } |
| mGlobalEvents.remove(eventName); |
| } |
| |
| /** |
| * Notifies WEEX that this event has occurred |
| * @param eventName WEEX register event |
| * @param module Events occur in this Module |
| * @param params The parameters to be notified to WEEX are required |
| */ |
| public void fireModuleEvent(String eventName, WXModule module,Map<String, Object> params) { |
| if (TextUtils.isEmpty(eventName) || module == null) { |
| return; |
| } |
| |
| Map<String, Object> event = new HashMap<>(); |
| event.put("type", eventName); |
| event.put("module", module.getModuleName()); |
| event.put("data", params); |
| |
| List<String> callbacks = module.getEventCallbacks(eventName); |
| if (callbacks != null) { |
| for (String callback : callbacks) { |
| SimpleJSCallback jsCallback = new SimpleJSCallback(mInstanceId, callback); |
| if (module.isOnce(callback)) { |
| jsCallback.invoke(event); |
| } else { |
| jsCallback.invokeAndKeepAlive(event); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Check whether the current module registered the event |
| * @param eventName EventName register in weex |
| * @param module Events occur in this Module |
| * @return register->true |
| */ |
| public boolean checkModuleEventRegistered(String eventName,WXModule module) { |
| if (module != null) { |
| List<String> events = module.getEventCallbacks(eventName); |
| if (events != null && events.size() > 0) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public WXPerformance getWXPerformance(){ |
| return mWXPerformance; |
| } |
| |
| public WXInstanceApm getApmForInstance() { |
| return mApmForInstance; |
| } |
| |
| public Map<String, Serializable> getUserTrackParams() { |
| return mUserTrackParams; |
| } |
| |
| public void addUserTrackParameter(String key,Serializable value){ |
| if(this.mUserTrackParams == null){ |
| this.mUserTrackParams = new ConcurrentHashMap<>(); |
| } |
| mUserTrackParams.put(key,value); |
| } |
| |
| public void clearUserTrackParameters(){ |
| if(this.mUserTrackParams != null){ |
| this.mUserTrackParams.clear(); |
| } |
| } |
| |
| public void removeUserTrackParameter(String key){ |
| if(this.mUserTrackParams != null){ |
| this.mUserTrackParams.remove(key); |
| } |
| } |
| |
| public int getMaxDeepLayer() { |
| return mMaxDeepLayer; |
| } |
| |
| public void setMaxDeepLayer(int maxDeepLayer) { |
| mMaxDeepLayer = maxDeepLayer; |
| mApmForInstance.updateMaxStats(WXInstanceApm.KEY_PAGE_STATS_MAX_DEEP_VIEW,maxDeepLayer); |
| } |
| |
| public void setMaxDomDeep(int maxDomDeep){ |
| mApmForInstance.updateMaxStats(WXInstanceApm.KEY_PAGE_STATS_MAX_DEEP_DOM,maxDomDeep); |
| if (null == mWXPerformance){ |
| return; |
| } |
| if (mWXPerformance.maxDeepVDomLayer <= maxDomDeep){ |
| mWXPerformance.maxDeepVDomLayer = maxDomDeep; |
| } |
| } |
| |
| public void onHttpStart(){ |
| if (!mEnd){ |
| mWXPerformance.fsRequestNum++; |
| } |
| } |
| |
| /** |
| * return md5, and bytes length |
| * */ |
| public String getTemplateInfo() { |
| String template = getTemplate(); |
| if(template == null){ |
| return " template md5 null ,httpHeader:" + JSONObject.toJSONString(responseHeaders); |
| } |
| if(TextUtils.isEmpty(template)){ |
| return " template md5 length 0 ,httpHeader" + JSONObject.toJSONString(responseHeaders); |
| } |
| try { |
| byte[] bts = template.getBytes("UTF-8"); |
| String sourceMD5 = WXFileUtils.md5(bts); |
| String sourceBase64MD5 = WXFileUtils.base64Md5(bts); |
| ArrayList<String> sourceMD5List = new ArrayList<>(); |
| ArrayList<String> sourceBase64MD5List = new ArrayList<>(); |
| sourceMD5List.add(sourceMD5); |
| sourceBase64MD5List.add(sourceBase64MD5); |
| responseHeaders.put("templateSourceMD5", sourceMD5List); |
| responseHeaders.put(SOURCE_TEMPLATE_BASE64_MD5, sourceBase64MD5List); |
| return " template md5 " + sourceMD5 + " length " + bts.length |
| + " base64 md5 " + sourceBase64MD5 |
| + " response header " + JSONObject.toJSONString(responseHeaders); |
| } catch (Exception e) { |
| return "template md5 getBytes error"; |
| } |
| |
| } |
| |
| /** |
| * check template header md5 match with header content-md5 |
| * */ |
| public boolean isContentMd5Match(){ |
| if(responseHeaders == null){ |
| return true; |
| } |
| List<String> contentMD5s = responseHeaders.get("Content-Md5"); |
| if(contentMD5s == null){ |
| contentMD5s = responseHeaders.get("content-md5"); |
| } |
| if(contentMD5s == null || contentMD5s.size() <= 0){ |
| return true; |
| } |
| String md5 = contentMD5s.get(0); |
| |
| List<String> sourceBase64Md5 = responseHeaders.get(SOURCE_TEMPLATE_BASE64_MD5); |
| if(sourceBase64Md5 == null){ |
| getTemplateInfo(); |
| sourceBase64Md5 = responseHeaders.get(SOURCE_TEMPLATE_BASE64_MD5); |
| } |
| if(sourceBase64Md5 == null || sourceBase64Md5.size() == 0){ |
| return true; |
| } |
| return md5.equals(sourceBase64Md5.get(0)); |
| } |
| |
| public String getTemplate() { |
| if(templateRef == null){ |
| return null; |
| } |
| return templateRef.get(); |
| } |
| |
| public void setTemplate(String template) { |
| this.templateRef = new WeakReference<String>(template); |
| } |
| |
| public interface NestedInstanceInterceptor { |
| void onCreateNestInstance(WXSDKInstance instance, NestedContainer container); |
| } |
| |
| public void OnVSync() { |
| if(mFixMultiThreadBug) { |
| if(!mPageDirty) { |
| return; |
| } |
| WXBridgeManager.getInstance().post(new Runnable() { |
| @Override |
| public void run() { |
| boolean forceLayout = WXBridgeManager.getInstance().notifyLayout(getInstanceId()); |
| if(forceLayout) { |
| WXBridgeManager.getInstance().forceLayout(getInstanceId()); |
| } |
| } |
| }); |
| } else { |
| boolean forceLayout = WXBridgeManager.getInstance().notifyLayout(getInstanceId()); |
| if(forceLayout) { |
| WXBridgeManager.getInstance().post(new Runnable() { |
| @Override |
| public void run() { |
| WXBridgeManager.getInstance().forceLayout(getInstanceId()); |
| } |
| }); |
| } |
| } |
| |
| |
| } |
| |
| public void addContentBoxMeasurement(long renderObjectPtr, ContentBoxMeasurement contentBoxMeasurement) { |
| mContentBoxMeasurements.put(renderObjectPtr, contentBoxMeasurement); |
| } |
| |
| public ContentBoxMeasurement getContentBoxMeasurement(long renderObjectPtr) { |
| return mContentBoxMeasurements.get(renderObjectPtr); |
| } |
| |
| |
| private void onInterceptInstanceEvent(String instanceId, String elementRef, String type, Map<String, Object> data, Map<String, Object> domChanges) { |
| if(this.mInstanceOnFireEventInterceptorList == null){ |
| return; |
| } |
| for(InstanceOnFireEventInterceptor instanceOnFireEventInterceptor : this.mInstanceOnFireEventInterceptorList){ |
| instanceOnFireEventInterceptor.onInterceptFireEvent(instanceId, elementRef, type, data, domChanges); |
| } |
| } |
| |
| public List<InstanceOnFireEventInterceptor> getInstanceOnFireEventInterceptorList(){ |
| if(this.mInstanceOnFireEventInterceptorList == null){ |
| this.mInstanceOnFireEventInterceptorList = new ArrayList<>(); |
| } |
| return mInstanceOnFireEventInterceptorList; |
| } |
| |
| |
| public void addInstanceOnFireEventInterceptor(InstanceOnFireEventInterceptor instanceOnFireEventInterceptor) { |
| if(instanceOnFireEventInterceptor == null){ |
| return; |
| } |
| if(!getInstanceOnFireEventInterceptorList().contains(instanceOnFireEventInterceptor)){ |
| getInstanceOnFireEventInterceptorList().add(instanceOnFireEventInterceptor); |
| } |
| } |
| |
| public String getRenderType() { |
| return mRenderType; |
| } |
| |
| public void setRenderType(String renderType) { |
| this.mRenderType = renderType; |
| } |
| |
| private static boolean isDisableSkipFrameworkInDataRender() { |
| IWXConfigAdapter adapter = WXSDKManager.getInstance().getWxConfigAdapter(); |
| if (adapter == null) { |
| return false; |
| } |
| String result = adapter.getConfig("wxeagle", "disable_skip_framework_init", "false"); |
| return "true".equals(result); |
| } |
| |
| public boolean isPageDirty() { |
| return mPageDirty; |
| } |
| |
| public void setPageDirty(boolean mPageDirty) { |
| this.mPageDirty = mPageDirty; |
| } |
| } |