/**
  * Method that returns the target view for the current resize frame
  *
  * @return The target view
  */
 View findTargetFromResizeFrame() {
   int count = getChildCount();
   for (int i = 0; i < count; i++) {
     View v = getChildAt(i);
     if (v.getX() < (mResizeFrame.getX() + (mResizeFrame.getWidth() / 2))
         && (v.getX() + v.getWidth()) > (mResizeFrame.getX() + (mResizeFrame.getWidth() / 2))
         && v.getY() < (mResizeFrame.getY() + (mResizeFrame.getHeight() / 2))
         && (v.getY() + v.getHeight()) > (mResizeFrame.getY() + (mResizeFrame.getHeight() / 2))) {
       return v;
     }
   }
   return null;
 }
 @Override
 public void onStartResize(int mode) {
   if (mResizeFrame == null) return;
   mOldResizeFrameLocation =
       new Rect(
           mResizeFrame.getLeft(),
           mResizeFrame.getTop(),
           mResizeFrame.getRight(),
           mResizeFrame.getBottom());
 }
  @Override
  public void onResize(int mode, int delta) {
    if (mTarget == null) return;
    if (mResizeFrame == null) return;

    int w = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
    int h = getMeasuredHeight() - (getPaddingTop() + getPaddingBottom());
    int minWidth = (w / mCols) + (w / mCols) / 2;
    int minHeight = (h / mRows) + (h / mRows) / 2;

    FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mResizeFrame.getLayoutParams();
    switch (mode) {
      case Gravity.LEFT:
        float newpos = mResizeFrame.getX() + delta;
        if ((delta < 0 && newpos < (getPaddingLeft() * -1))
            || (delta > 0 && newpos > (mResizeFrame.getX() + params.width - minWidth))) {
          return;
        }
        mResizeFrame.setX(newpos);
        params.width -= delta;
        break;
      case Gravity.RIGHT:
        if ((delta < 0 && ((params.width + delta) < minWidth))
            || (delta > 0
                && (mResizeFrame.getX() + delta + params.width)
                    > (getPaddingLeft() + getMeasuredWidth()))) {
          return;
        }
        params.width += delta;
        break;
      case Gravity.TOP:
        newpos = mResizeFrame.getY() + delta;
        if ((delta < 0 && newpos < (getPaddingTop() * -1))
            || (delta > 0 && newpos > (mResizeFrame.getY() + params.height - minHeight))) {
          return;
        }
        mResizeFrame.setY(newpos);
        params.height -= delta;
        break;
      case Gravity.BOTTOM:
        if ((delta < 0 && ((params.height + delta) < minHeight))
            || (delta > 0
                && (mResizeFrame.getY() + delta + params.height)
                    > (getPaddingTop() + getMeasuredHeight()))) {
          return;
        }
        params.height += delta;
        break;

      default:
        break;
    }
    mResizeFrame.setLayoutParams(params);
  }
  /**
   * Method that converts the resize frame to a dispostion reference
   *
   * @return Disposition The disposition reference
   */
  private Disposition resizerToDisposition() {
    int w = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
    int h = getMeasuredHeight() - (getPaddingTop() + getPaddingBottom());
    int cw = w / mCols;
    int ch = h / mRows;

    // Remove overlapped areas
    Disposition resizer = new Disposition();
    resizer.x = Math.round(mResizeFrame.getX() / cw);
    resizer.y = Math.round(mResizeFrame.getY() / ch);
    resizer.w = Math.round(mResizeFrame.getWidth() / cw);
    resizer.h = Math.round(mResizeFrame.getHeight() / ch);

    // Fix disposition (limits)
    resizer.x = Math.max(resizer.x, 0);
    resizer.y = Math.max(resizer.y, 0);
    resizer.w = Math.min(resizer.w, mCols - resizer.x);
    resizer.h = Math.min(resizer.h, mRows - resizer.y);

    return resizer;
  }
  /**
   * Method that sets the disposition to draw on this view
   *
   * @param dispositions The dispositions to draw
   * @param cols The number of columns
   * @param rows The number of rows
   * @param animate If should animate the view
   */
  public void setDispositions(List<Disposition> dispositions, int cols, int rows, boolean animate) {
    mDispositions = dispositions;
    mCols = cols;
    mRows = rows;

    // Remove all the current views and add the new ones
    recreateDispositions(animate);
    if (mResizeFrame != null) {
      mResizeFrame.setVisibility(View.GONE);
    }
    mChanged = false;
  }
  /**
   * Method that select a view as the target of to resize
   *
   * @param v The target view
   */
  boolean selectTarget(View v) {
    // Do not do long click if we do not have a target
    if (mTarget != null && v.equals(mTarget)) return false;
    if (mResizeFrame == null) return false;

    // Show the resize frame view just in place of the current clicked view

    mResizeFrame.hide();
    FrameLayout.LayoutParams frameParams =
        (FrameLayout.LayoutParams) mResizeFrame.getLayoutParams();
    int padding = mInternalPadding + mResizeFrame.getNeededPadding();
    frameParams.width = v.getWidth() + (padding * 2);
    frameParams.height = v.getHeight() + (padding * 2);
    mResizeFrame.setX(v.getX() - padding);
    mResizeFrame.setY(v.getY() - padding);
    mResizeFrame.show();

    // Save the new view
    mTarget = v;
    if (mOnFrameSelectedListener != null) {
      mOnFrameSelectedListener.onFrameSelectedListener(v);
    }
    return true;
  }
  /** Method that request the deletion of the current selected frame */
  @SuppressWarnings("boxing")
  public void deleteCurrentFrame() {
    if (mTarget == null) return;
    if (mResizeFrame == null) return;

    final Disposition targetDisposition = resizerToDisposition();

    // Get valid dispositions to move
    final List<Disposition> adjacents = findAdjacentsDispositions(targetDisposition);
    if (adjacents == null) {
      // Nothing to do
      Toast.makeText(
              getContext(), R.string.pref_disposition_unable_delete_advise, Toast.LENGTH_SHORT)
          .show();
      return;
    }

    // Hide resizer
    mResizeFrame.setVisibility(View.GONE);

    // Animate adjacents views
    List<Animator> animators = new ArrayList<Animator>();
    animators.add(ObjectAnimator.ofFloat(mTarget, "scaleX", 1.0f, 0.0f));
    animators.add(ObjectAnimator.ofFloat(mTarget, "scaleY", 1.0f, 0.0f));

    Disposition first = null;
    for (Disposition adjacent : adjacents) {
      // Extract the view and remove from dispositions
      View v = findViewFromRect(getLocationFromDisposition(adjacent));
      mDispositions.remove(adjacent);

      // Clone first disposition
      if (first == null) {
        first = new Disposition();
        first.x = adjacent.x;
        first.y = adjacent.y;
        first.w = adjacent.w;
        first.h = adjacent.h;
      }

      // Add animators and fix the adjacent
      if (v != null) {
        if (first.x < targetDisposition.x) {
          // From Left to Right
          int width = mTarget.getWidth() + mInternalPadding;
          animators.add(
              ValueAnimator.ofObject(
                  new Evaluators.WidthEvaluator(v), v.getWidth(), v.getWidth() + width));

          // Update the adjacent
          adjacent.w += targetDisposition.w;
          mDispositions.add(adjacent);

        } else if (first.x > targetDisposition.x) {
          // From Right to Left
          int width = mTarget.getWidth() + mInternalPadding;
          animators.add(
              ValueAnimator.ofObject(
                  new Evaluators.WidthEvaluator(v), v.getWidth(), v.getWidth() + width));
          animators.add(ObjectAnimator.ofFloat(v, "x", v.getX(), mTarget.getX()));

          // Update the adjacent
          adjacent.x = targetDisposition.x;
          adjacent.w += targetDisposition.w;
          mDispositions.add(adjacent);

        } else if (first.y < targetDisposition.y) {
          // From Top to Bottom
          int height = mTarget.getHeight() + mInternalPadding;
          animators.add(
              ValueAnimator.ofObject(
                  new Evaluators.HeightEvaluator(v), v.getHeight(), v.getHeight() + height));

          // Update the adjacent
          adjacent.h += targetDisposition.h;
          mDispositions.add(adjacent);

        } else if (first.y > targetDisposition.y) {
          // From Bottom to Top
          int height = mTarget.getHeight() + mInternalPadding;
          animators.add(
              ValueAnimator.ofObject(
                  new Evaluators.HeightEvaluator(v), v.getHeight(), v.getHeight() + height));
          animators.add(ObjectAnimator.ofFloat(v, "y", v.getY(), mTarget.getY()));

          // Update the adjacent
          adjacent.y = targetDisposition.y;
          adjacent.h += targetDisposition.h;
          mDispositions.add(adjacent);
        }
      }
    }
    if (animators.size() > 0) {
      AnimatorSet animSet = new AnimatorSet();
      animSet.playTogether(animators);
      animSet.setDuration(getResources().getInteger(R.integer.disposition_hide_anim));
      animSet.setInterpolator(new AccelerateInterpolator());
      animSet.addListener(
          new AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
              // Ignore
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
              // Ignore
            }

            @Override
            public void onAnimationEnd(Animator animation) {
              finishDeleteAnimation(targetDisposition);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
              finishDeleteAnimation(targetDisposition);
            }
          });
      animSet.start();
    }
  }
 /**
  * Method that sets the resize frame view
  *
  * @param resizeFrame The resize frame view
  */
 public void setResizeFrame(ResizeFrame resizeFrame) {
   mResizeFrame = resizeFrame;
   mResizeFrame.setOnResizeListener(this);
 }