content: /**
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  package org.apache.weex;
  
  import android.net.Uri;
  import android.text.TextUtils;
  
  import org.apache.weex.adapter.IWXUserTrackAdapter;
  import org.apache.weex.common.WXErrorCode;
  import org.apache.weex.common.WXPerformance;
  import org.apache.weex.common.WXRenderStrategy;
  import org.apache.weex.common.WXResponse;
  import org.apache.weex.performance.WXInstanceApm;
  import org.apache.weex.tracing.WXTracing;
  import org.apache.weex.utils.WXLogUtils;
  import org.apache.weex.utils.tools.LogDetail;
  
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import org.apache.weex.adapter.IWXHttpAdapter.OnHttpListener;
  
  /**
   * load bundle js listener
   */
  public class WXHttpListener implements OnHttpListener {
  
      private String pageName;
      private Map<String, Object> options;
      private String jsonInitData;
      private WXRenderStrategy flag;
      private WXSDKInstance instance;
      private long startRequestTime;
      private int traceId;
      private WXPerformance mWXPerformance;
      private WXInstanceApm mApmForInstance;
      private IWXUserTrackAdapter mUserTrackAdapter;
      public boolean isPreDownLoadMode = false;
      private boolean isInstanceReady =false;
      private boolean isResponseHasWait = false;
      private WXResponse mResponse;
      private LogDetail mLogDetail;
  
      private String mBundleUrl;
  
      public WXHttpListener(WXSDKInstance instance) {
          if(instance != null) {
              mLogDetail = instance.mTimeCalculator.createLogDetail("downloadBundleJS");
          }
          this.instance = instance;
          this.traceId = WXTracing.nextId();
          this.mWXPerformance = instance.getWXPerformance();
          this.mApmForInstance = instance.getApmForInstance();
          this.mUserTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
          if (WXTracing.isAvailable()) {
              WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", instance.getInstanceId(), -1);
              event.iid = instance.getInstanceId();
              event.tname = "Network";
              event.ph = "B";
              event.traceId = traceId;
              event.submit();
          }
      }
  
      public WXHttpListener(WXSDKInstance instance, String bundleUrl) {
          this(instance);
          this.startRequestTime = System.currentTimeMillis();
          this.mBundleUrl = bundleUrl;
      }
  
      public WXHttpListener(WXSDKInstance instance, String pageName, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag, long startRequestTime) {
          this(instance);
          this.pageName = pageName;
          this.options = options;
          this.jsonInitData = jsonInitData;
          this.flag = flag;
          this.startRequestTime = startRequestTime;
          this.mBundleUrl = instance.getBundleUrl();
      }
  
      public void setSDKInstance(WXSDKInstance instance) {
          this.instance = instance;
      }
  
      protected WXSDKInstance getInstance() {
          return instance;
      }
  
      @Override
      public void onHttpStart() {
          if (this.instance != null
                  && this.instance.getWXStatisticsListener() != null) {
              this.instance.getWXStatisticsListener().onHttpStart();
              if(mLogDetail != null) {
                  mLogDetail.taskStart();
              }
          }
      }
  
      @Override
      public void onHeadersReceived(int statusCode, Map<String,List<String>> headers) {
          if (this.instance != null
                  && this.instance.getWXStatisticsListener() != null) {
              this.instance.getWXStatisticsListener().onHeadersReceived();
              this.instance.onHttpStart();
          }
          if(this.instance != null
                  && this.instance.responseHeaders != null
                  && headers != null){
              this.instance.responseHeaders.putAll(headers);
          }
      }
  
      @Override
      public void onHttpUploadProgress(int uploadProgress) {
  
      }
  
      @Override
      public void onHttpResponseProgress(int loadedLength) {
          instance.getApmForInstance().extInfo.put(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH,loadedLength);
      }
  
      @Override
      public void onHttpFinish(WXResponse response) {
          if(mLogDetail != null) {
              mLogDetail.taskEnd();
          }
          if (this.instance != null
                  && this.instance.getWXStatisticsListener() != null) {
              this.instance.getWXStatisticsListener().onHttpFinish();
          }
  
          if (WXTracing.isAvailable()) {
              WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", instance.getInstanceId(), -1);
              event.traceId = traceId;
              event.tname = "Network";
              event.ph = "E";
              event.extParams = new HashMap<>();
              if (response != null && response.originalData != null) {
                  event.extParams.put("BundleSize", response.originalData.length);
              }
              event.submit();
          }
  
          mWXPerformance.networkTime = System.currentTimeMillis() - startRequestTime;
          if(null!= response && response.extendParams!=null){
              mApmForInstance.updateRecordInfo(response.extendParams);
              Object actualNetworkTime=response.extendParams.get("actualNetworkTime");
              mWXPerformance.actualNetworkTime=actualNetworkTime instanceof Long?(long)actualNetworkTime:0;
  
              Object pureNetworkTime=response.extendParams.get("pureNetworkTime");
              mWXPerformance.pureNetworkTime=pureNetworkTime instanceof Long?(long)pureNetworkTime:0;
  
              Object connectionType=response.extendParams.get("connectionType");
              mWXPerformance.connectionType=connectionType instanceof String?(String)connectionType:"";
  
              Object packageSpendTime=response.extendParams.get("packageSpendTime");
              mWXPerformance.packageSpendTime=packageSpendTime instanceof Long ?(long)packageSpendTime:0;
  
              Object syncTaskTime=response.extendParams.get("syncTaskTime");
              mWXPerformance.syncTaskTime=syncTaskTime instanceof Long ?(long)syncTaskTime:0;
  
              Object requestType=response.extendParams.get("requestType");
              mWXPerformance.requestType=requestType instanceof String?(String)requestType:"none";
  
              Object cacheType = response.extendParams.get(WXPerformance.Dimension.cacheType.toString());
              if(cacheType instanceof String){
                  mWXPerformance.cacheType = (String) cacheType;
              }
  
              Object zCacheInfo = response.extendParams.get("zCacheInfo");
              mWXPerformance.zCacheInfo = zCacheInfo instanceof String?(String)zCacheInfo:"";
  
              if(isNet(mWXPerformance.requestType) && mUserTrackAdapter!=null){
                  WXPerformance performance=new WXPerformance(instance.getInstanceId());
                  if(!TextUtils.isEmpty(mBundleUrl)){
                      try {
                          performance.args= Uri.parse(mBundleUrl).buildUpon().clearQuery().toString();
                      } catch (Exception e) {
                          performance.args=pageName;
                      }
                  }
                  if(!"200".equals(response.statusCode)){
                      performance.errCode= WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
                      performance.appendErrMsg(response.errorCode);
                      performance.appendErrMsg("|");
                      performance.appendErrMsg(response.errorMsg);
  
                  }else if("200".equals(response.statusCode) && (response.originalData==null || response.originalData.length<=0)){
                      performance.errCode=WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
                      performance.appendErrMsg(response.statusCode);
                      performance.appendErrMsg("|template is null!");
                  }else {
                      performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode();
                  }
  
                  if (mUserTrackAdapter != null) {
                      mUserTrackAdapter.commit(instance.getContext(), null, IWXUserTrackAdapter.JS_DOWNLOAD, performance, null);
                  }
              }
          }
  
          if (isPreDownLoadMode){
              if (isInstanceReady){
                  WXLogUtils.d("test->", "DownLoad didHttpFinish on http" );
                  didHttpFinish(response);
              }else {
                  WXLogUtils.d("test->", "DownLoad end before activity created" );
                  mResponse = response;
                  isResponseHasWait = true;
              }
          }else {
              didHttpFinish(response);
          }
  
      }
  
      public void onInstanceReady(){
          if (!isPreDownLoadMode){
              return;
          }
          this.isInstanceReady = true;
          if (isResponseHasWait){
              WXLogUtils.d("test->", "preDownLoad didHttpFinish on ready" );
              this.didHttpFinish(mResponse);
          }
  
      }
  
      private void didHttpFinish(WXResponse response){
          String wxErrorCode = WXInstanceApm.VALUE_ERROR_CODE_DEFAULT;
          if (response!=null && response.originalData!=null && TextUtils.equals("200", response.statusCode)) {
              mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END);
              onSuccess(response);
  
              // check content-type
          } else if (TextUtils.equals(WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode(),
                  response.statusCode)) {
              WXLogUtils.e("user intercept: WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR");
              wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode();
              instance.onRenderError(wxErrorCode,
                      "|response.errorMsg==" + response.errorMsg +
                              "|instance bundleUrl = \n" + instance.getBundleUrl() +
                              "|instance requestUrl = \n" + Uri.decode(WXSDKInstance.requestUrl)
              );
              onFail(response);
  
              // check content-length
          } else if (response!=null && response.originalData!=null && TextUtils.equals("-206", response.statusCode)) {
              WXLogUtils.e("user intercept: WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED");
              wxErrorCode =  WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode();
              instance.onRenderError(wxErrorCode ,
                      WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode() +
                              "|response.errorMsg==" + response.errorMsg
              );
              onFail(response);
          }
          else {
              wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED.getErrorCode();
              instance.onRenderError(wxErrorCode,
                      response.errorMsg);
              onFail(response);
          }
          if (!WXInstanceApm.VALUE_ERROR_CODE_DEFAULT.equals(wxErrorCode)){
              mApmForInstance.addProperty(WXInstanceApm.KEY_PROPERTIES_ERROR_CODE,wxErrorCode);
          }
      }
  
      private boolean isNet(String requestType){
  
          return "network".equals(requestType) || "2g".equals(requestType) || "3g".equals(requestType)
                  || "4g".equals(requestType) || "wifi".equals(requestType) || "other".equals(requestType)
                  || "unknown".equals(requestType);
      }
  
      public void onSuccess(WXResponse response) {
          if (flag==WXRenderStrategy.DATA_RENDER_BINARY){
              instance.render(pageName, response.originalData, options, jsonInitData);
          }else {
              String template = new String(response.originalData);
              instance.render(pageName, template, options, jsonInitData, flag);
          }
      }
  
      public void onFail(WXResponse response) {
  
      }
  }
  
  
  