@Override
  public void onComplete(
      final Bitmap result, MoaActionList actions, HashMap<String, String> trackingAttributes) {
    logger.info("onComplete: " + android.os.Debug.getNativeHeapAllocatedSize());
    Tracker.recordTag(
        mCurrentEntry.name.name().toLowerCase(Locale.US) + ": applied", trackingAttributes);

    if (result != null) {
      if (mCurrentEffect instanceof ContentPanel) {
        ContentPanel panel = (ContentPanel) mCurrentEffect;
        final boolean changed = BitmapUtils.compareBySize(mBitmap, result);
        setNextBitmap(result, true, changed ? null : panel.getContentDisplayMatrix());
      } else {
        setNextBitmap(result, false);
      }

    } else {
      logger.error("Error: returned bitmap is null!");
      setNextBitmap(mBitmap, true);
    }

    onClose(true);

    if (mHiResEnabled) {
      // send the actions...
      if (null == actions) logger.error("WTF actionlist is null!!!!");

      HiResService service = getService(HiResService.class);
      if (service.isRunning()) {
        service.execute(mSessionId, mApiKey, actions);
      }
    }

    if (null != mHiResListener) {
      mHiResListener.OnApplyActions(actions);
    }
  }
  @Override
  public void cancel() {

    logger.info("FilterManager::cancel");

    if (!getEnabled() || !isOpened()) return;
    if (mCurrentEffect == null)
      throw new IllegalStateException("there is no current effect active in the context");

    Tracker.recordTag(mCurrentEntry.name.name().toLowerCase(Locale.US) + ": cancelled");

    // send the cancel event to the effect
    mCurrentEffect.onCancelled();

    // check changed image
    if (mCurrentEffect.getIsChanged()) {
      // panel is changed, restore the original bitmap

      if (mCurrentEffect instanceof ContentPanel) {
        ContentPanel panel = (ContentPanel) mCurrentEffect;
        setNextBitmap(mBitmap, true, panel.getContentDisplayMatrix());
      } else {
        setNextBitmap(mBitmap, false);
      }

    } else {
      // panel is not changed
      if (mCurrentEffect instanceof ContentPanel) {
        ContentPanel panel = (ContentPanel) mCurrentEffect;
        setNextBitmap(mBitmap, true, panel.getContentDisplayMatrix());
      } else {
        setNextBitmap(mBitmap, false);
      }
    }
    onClose(false);
  }
  /**
   * Sets the current state.
   *
   * @param newState the new current state
   */
  private void setCurrentState(final STATE newState) {
    if (newState != mCurrentState) {
      final STATE previousState = mCurrentState;
      mCurrentState = newState;

      switch (newState) {
        case OPENING:
          mCurrentEffect.setOnPreviewListener(this);
          mCurrentEffect.setOnApplyResultListener(this);
          mCurrentEffect.setOnErrorListener(this);
          mCurrentEffect.setOnProgressListener(this);

          if (mCurrentEffect instanceof ContentPanel)
            ((ContentPanel) mCurrentEffect).setOnReadyListener(this);

          mHandler.sendEmptyMessage(FilterManager.STATE_OPENING);
          break;

        case OPENED:
          mCurrentEffect.onActivate();
          mHandler.sendEmptyMessage(FilterManager.STATE_OPENED);

          if (!(mCurrentEffect instanceof ContentPanel)) {
            mHandler.sendEmptyMessage(STATE_READY);
          }

          break;

        case CLOSING:
          mHandler.sendEmptyMessage(FilterManager.STATE_CLOSING);

          mCurrentEffect.onDeactivate();
          if (mCurrentEffect instanceof ContentPanel) {
            ((ContentPanel) mCurrentEffect).setOnReadyListener(null);
          }

          mHandler.postDelayed(
              new Runnable() {

                @Override
                public void run() {
                  if (null != mBitmapChangeListener) mBitmapChangeListener.onClearColorFilter();
                  mContext.getDrawingImageContainer().removeAllViews();
                  mContext.deactivatePopupContainer();
                }
              },
              100);
          break;

        case CLOSED_CANCEL:
        case CLOSED_CONFIRMED:
          mContext.getOptionsPanelContainer().removeAllViews();

          if (previousState != STATE.DISABLED) {
            mCurrentEffect.onDestroy();
            mCurrentEffect.setOnPreviewListener(null);
            mCurrentEffect.setOnApplyResultListener(null);
            mCurrentEffect.setOnErrorListener(null);
            mCurrentEffect.setOnProgressListener(null);
            mCurrentEffect = null;
            mCurrentEntry = null;
          }

          mHandler.sendEmptyMessage(FilterManager.STATE_CLOSED);

          if ((newState == STATE.CLOSED_CONFIRMED) && (previousState != STATE.DISABLED))
            if (mToolListener != null) mToolListener.onToolCompleted();
          System.gc();
          break;

        case DISABLED:
          mHandler.sendEmptyMessage(FilterManager.STATE_DISABLED);
          break;
      }
    }
  }