@Override
  protected void onAfterInputEvent(View rootView, InputEvent input) {
    super.onAfterInputEvent(rootView, input);
    if (!enabled||(input instanceof MotionEvent)==false) {
      return ;
    }
    MotionEvent event = (MotionEvent) input;
    int action = event.getActionMasked();
    switch (action) {
      case MotionEvent.ACTION_DOWN:
      case MotionEvent.ACTION_POINTER_DOWN: {
        int index = (action == ACTION_DOWN) ? 0 : event.getActionIndex();
        if (pointerOne == INVALID_POINTER_ID) {
          pointerOne = event.getPointerId(index);
          lastOneX = event.getX(index);
          lastOneY = event.getY(index);
          if (DEBUG) log("Got pointer 1!  id: %s  x: %s  y: %s", pointerOne, lastOneY, lastOneY);
        } else if (pointerTwo == INVALID_POINTER_ID) {
          pointerTwo = event.getPointerId(index);
          lastTwoX = event.getX(index);
          lastTwoY = event.getY(index);
          if (DEBUG) log("Got pointer 2!  id: %s  x: %s  y: %s", pointerTwo, lastTwoY, lastTwoY);
        } else {
          if (DEBUG) log("Ignoring additional pointer.  id: %s", event.getPointerId(index));
        }
        break;
      }

      case MotionEvent.ACTION_MOVE: {
        if (pointerTwo == INVALID_POINTER_ID) {
          // Single pointer controlling 3D rotation.
          for (int i = 0, count = event.getPointerCount(); i < count; i++) {
            if (pointerOne == event.getPointerId(i)) {
              float eventX = event.getX(i);
              float eventY = event.getY(i);
              float dx = eventX - lastOneX;
              float dy = eventY - lastOneY;
              float drx = 90 * (dx / getWidth());
              float dry = 90 * (-dy / getHeight()); // Invert Y-axis.
              // An 'x' delta affects 'y' rotation and vise versa.
              rotationY = Math.min(Math.max(rotationY + drx, ROTATION_MIN), ROTATION_MAX);
              rotationX = Math.min(Math.max(rotationX + dry, ROTATION_MIN), ROTATION_MAX);
              if (DEBUG) {
                log("Single pointer moved (%s, %s) affecting rotation (%s, %s).", dx, dy, drx, dry);
              }

              lastOneX = eventX;
              lastOneY = eventY;

              invalidate();
            }
          }
        } else {
          // We know there's two pointers and we only care about pointerOne and pointerTwo
          int pointerOneIndex = event.findPointerIndex(pointerOne);
          int pointerTwoIndex = event.findPointerIndex(pointerTwo);

          float xOne = event.getX(pointerOneIndex);
          float yOne = event.getY(pointerOneIndex);
          float xTwo = event.getX(pointerTwoIndex);
          float yTwo = event.getY(pointerTwoIndex);

          float dxOne = xOne - lastOneX;
          float dyOne = yOne - lastOneY;
          float dxTwo = xTwo - lastTwoX;
          float dyTwo = yTwo - lastTwoY;

          if (multiTouchTracking == TRACKING_UNKNOWN) {
            float adx = Math.abs(dxOne) + Math.abs(dxTwo);
            float ady = Math.abs(dyOne) + Math.abs(dyTwo);

            if (adx > slop * 2 || ady > slop * 2) {
              if (adx > ady) {
                // Left/right movement wins. Track horizontal.
                multiTouchTracking = TRACKING_HORIZONTALLY;
              } else {
                // Up/down movement wins. Track vertical.
                multiTouchTracking = TRACKING_VERTICALLY;
              }
            }
          }

          if (multiTouchTracking == TRACKING_VERTICALLY) {
            if (yOne >= yTwo) {
              zoom += dyOne / getHeight() - dyTwo / getHeight();
            } else {
              zoom += dyTwo / getHeight() - dyOne / getHeight();
            }

            zoom = Math.min(Math.max(zoom, ZOOM_MIN), ZOOM_MAX);
            invalidate();
          } else if (multiTouchTracking == TRACKING_HORIZONTALLY) {
            if (xOne >= xTwo) {
              spacing += (dxOne / getWidth() * SPACING_MAX) - (dxTwo / getWidth() * SPACING_MAX);
            } else {
              spacing += (dxTwo / getWidth() * SPACING_MAX) - (dxOne / getWidth() * SPACING_MAX);
            }

            spacing = Math.min(Math.max(spacing, SPACING_MIN), SPACING_MAX);
            invalidate();
          }

          if (multiTouchTracking != TRACKING_UNKNOWN) {
            lastOneX = xOne;
            lastOneY = yOne;
            lastTwoX = xTwo;
            lastTwoY = yTwo;
          }
        }
        break;
      }

      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_POINTER_UP: {
        int index = (action != ACTION_POINTER_UP) ? 0 : event.getActionIndex();
        int pointerId = event.getPointerId(index);
        if (pointerOne == pointerId) {
          // Shift pointer two (real or invalid) up to pointer one.
          pointerOne = pointerTwo;
          lastOneX = lastTwoX;
          lastOneY = lastTwoY;
          if (DEBUG) log("Promoting pointer 2 (%s) to pointer 1.", pointerTwo);
          // Clear pointer two and tracking.
          pointerTwo = INVALID_POINTER_ID;
          multiTouchTracking = TRACKING_UNKNOWN;
        } else if (pointerTwo == pointerId) {
          if (DEBUG) log("Lost pointer 2 (%s).", pointerTwo);
          pointerTwo = INVALID_POINTER_ID;
          multiTouchTracking = TRACKING_UNKNOWN;
        }
        break;
      }
    }
  }
Returns true when view layers draw their IDs.
saklib/src/main/java/com/wanjian/sak/layer/impl/ScalpelFrameLayout.java