/*
  Result CB Code
  */
  @SuppressLint({
    "InlinedApi",
    "NewApi"
  }) /* suppress AsyncTask.THREAD_POOL_EXECUTOR warning for < HONEYCOMB */
  private void fireResultCB(final ResultCode result) {
    if (hasFailed) return;

    AdRequester requester = this.adFetcher.get();
    // if resultCB is empty don't fire resultCB, and just continue to next ad
    if ((currentAd == null) || StringUtil.isEmpty(currentAd.getResultCB())) {
      if (result == ResultCode.SUCCESS) return;
      Clog.w(Clog.mediationLogTag, Clog.getString(R.string.fire_cb_result_null));
      // just making sure
      if (requester == null) {
        Clog.e(Clog.httpRespLogTag, Clog.getString(R.string.fire_cb_requester_null));
        return;
      }
      requester.onReceiveResponse(null);
      return;
    }

    boolean ignoreResult = false; // default is to not ignore
    if ((requester != null) && (requester.getMediatedAds() != null)) {
      // ignore resultCB except on the last mediated ad
      ignoreResult = requester.getMediatedAds().size() > 0;
    }

    // ignore resultCB if succeeded already
    if (result == ResultCode.SUCCESS) {
      ignoreResult = true;
    }

    // fire call to result cb url
    ResultCBRequest cb =
        new ResultCBRequest(
            requester,
            currentAd.getResultCB(),
            result,
            currentAd.getExtras(),
            ignoreResult,
            getLatencyParam(),
            getTotalLatencyParam(requester));

    // Spawn GET call
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
      cb.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    } else {
      cb.execute();
    }

    // if currentAd failed and next ad is available, continue to next ad
    if (ignoreResult && result != ResultCode.SUCCESS) {
      if (requester != null) {
        requester.onReceiveResponse(null);
      }
    }
  }
  private MediatedNativeAdController(
      MediatedAd currentAd, NativeAdFetcher adFetcher, NativeAdRequest.AdDispatcher listener) {
    if (currentAd == null) {
      Clog.e(Clog.mediationLogTag, Clog.getString(R.string.mediated_no_ads));
      errorCode = ResultCode.UNABLE_TO_FILL;
    } else {
      Clog.d(
          Clog.mediationLogTag,
          Clog.getString(R.string.instantiating_class, currentAd.getClassName()));

      this.adFetcher = new WeakReference<NativeAdFetcher>(adFetcher);
      this.listener = listener;
      this.currentAd = currentAd;

      startTimeout();
      markLatencyStart();

      try {
        Class<?> c = Class.forName(currentAd.getClassName());
        MediatedNativeAd ad = (MediatedNativeAd) c.newInstance();
        if (adFetcher.getRequestParams() != null) {
          ad.requestNativeAd(
              adFetcher.getRequestParams().getContext(),
              currentAd.getId(),
              this,
              adFetcher.getRequestParams().getTargetingParameters());
        } else {
          errorCode = ResultCode.INVALID_REQUEST;
        }
      } catch (ClassNotFoundException e) {
        // exception in Class.forName
        handleInstantiationFailure(e, currentAd.getClassName());
      } catch (ClassCastException e) {
        // exception in casting instance to MediatedNativeAd
        handleInstantiationFailure(e, currentAd.getClassName());
      } catch (LinkageError e) {
        // error in Class.forName
        // also catches subclass ExceptionInInitializerError
        handleInstantiationFailure(e, currentAd.getClassName());
      } catch (InstantiationException e) {
        // exception in Class.newInstance
        handleInstantiationFailure(e, currentAd.getClassName());
      } catch (IllegalAccessException e) {
        // exception in Class.newInstance
        handleInstantiationFailure(e, currentAd.getClassName());
      }
    }
    if (errorCode != null) {
      onAdFailed(errorCode);
    }
  }