捕获时如何创建矩形区域(相机)

时间:2014-11-05 14:04:59

标签: android

我想实现这样的目标:

enter image description here

所以你捕获和处理的唯一东西就是矩形区域。 我需要这个,因为我想做一些OCR,我不想要整个屏幕。

1 个答案:

答案 0 :(得分:1)

也许可以帮助你这个来源,(在相机预览的顶部绘制一个边界框来捕捉部分图像) Preview Camera Rectangle

代码:

清单:

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <com.camera.preview.Preview
        android:id="@+id/preview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    </com.camera.preview.Preview>

    <com.camera.preview.TouchView
        android:id="@+id/left_top_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    </com.camera.preview.TouchView>

    <ImageView
        android:id="@+id/startcamerapreview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:src="@drawable/camera" />

</RelativeLayout>

main.xml中

public class CameraPreview extends Activity implements SensorEventListener {

private Preview mPreview; 
private ImageView mTakePicture;
private TouchView mView;

private boolean mAutoFocus = true;

private boolean mFlashBoolean = false;

private SensorManager mSensorManager;
private Sensor mAccel;
private boolean mInitialized = false;
private float mLastX = 0;
private float mLastY = 0;
private float mLastZ = 0;
private Rect rec = new Rect();

private int mScreenHeight;
private int mScreenWidth;

private boolean mInvalidate = false;

private File mLocation = new File(Environment.
        getExternalStorageDirectory(),"test.jpg");

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //Log.i(TAG, "onCreate()");
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

    // display our (only) XML layout - Views already ordered
    setContentView(R.layout.main);

    // the accelerometer is used for autofocus
    mSensorManager = (SensorManager) getSystemService(Context.
            SENSOR_SERVICE);
    mAccel = mSensorManager.getDefaultSensor(Sensor.
            TYPE_ACCELEROMETER);

    // get the window width and height to display buttons
    // according to device screen size
    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    mScreenHeight = displaymetrics.heightPixels;
    mScreenWidth = displaymetrics.widthPixels;
    // I need to get the dimensions of this drawable to set margins
    // for the ImageView that is used to take pictures
    Drawable mButtonDrawable = this.getResources().
    getDrawable(R.drawable.camera);

    mTakePicture = (ImageView) findViewById(R.id.startcamerapreview);

    // setting where I will draw the ImageView for taking pictures
    LayoutParams lp = new LayoutParams(mTakePicture.getLayoutParams());
    lp.setMargins((int)((double)mScreenWidth*.85),
            (int)((double)mScreenHeight*.70) ,
            (int)((double)mScreenWidth*.85)+mButtonDrawable.
            getMinimumWidth(), 
            (int)((double)mScreenHeight*.70)+mButtonDrawable.
            getMinimumHeight());
    mTakePicture.setLayoutParams(lp);
    // rec is used for onInterceptTouchEvent. I pass this from the
    // highest to lowest layer so that when this area of the screen
    // is pressed, it ignores the TouchView events and passes it to
    // this activity so that the button can be pressed.
    rec.set((int)((double)mScreenWidth*.85),
            (int)((double)mScreenHeight*.10) ,
            (int)((double)mScreenWidth*.85)+mButtonDrawable.getMinimumWidth(), 
            (int)((double)mScreenHeight*.70)+mButtonDrawable.getMinimumHeight());
    mButtonDrawable = null;
    mTakePicture.setOnClickListener(previewListener);
    // get our Views from the XML layout
    mPreview = (Preview) findViewById(R.id.preview);
    mView = (TouchView) findViewById(R.id.left_top_view);
    mView.setRec(rec);

}

// this is the autofocus call back
private AutoFocusCallback myAutoFocusCallback = new AutoFocusCallback(){

    public void onAutoFocus(boolean autoFocusSuccess, Camera arg1) {
        //Wait.oneSec();
        mAutoFocus = true;
    }};

    // with this I get the ratio between screen size and pixels
    // of the image so I can capture only the rectangular area of the
    // image and save it.
    public Double[] getRatio(){
        Size s = mPreview.getCameraParameters().getPreviewSize();
        double heightRatio = (double)s.height/(double)mScreenHeight;
        double widthRatio = (double)s.width/(double)mScreenWidth;
        Double[] ratio = {heightRatio,widthRatio};
        return ratio;
    }

    // I am not using this in this example, but its there if you want
    // to turn on and off the flash.
    private OnClickListener flashListener = new OnClickListener(){

        @Override
        public void onClick(View v) {
            if (mFlashBoolean){
                mPreview.setFlash(false);
            }
            else{
                mPreview.setFlash(true);
            }
            mFlashBoolean = !mFlashBoolean;
        }

    };

    // This method takes the preview image, grabs the rectangular
    // part of the image selected by the bounding box and saves it.
    // A thread is needed to save the picture so not to hold the UI thread.
    private OnClickListener previewListener = new OnClickListener() {

        @Override
        public void onClick(View v) {
            if (mAutoFocus){
                mAutoFocus = false;
                //mPreview.setCameraFocus(myAutoFocusCallback);
                Wait.oneSec();
                Thread tGetPic = new Thread( new Runnable() {
                    public void run() {
                        Double[] ratio = getRatio();
                        int left = (int) (ratio[1]*(double)mView.getmLeftTopPosX());
                        // 0 is height
                        int top = (int) (ratio[0]*(double)mView.getmLeftTopPosY());

                        int right = (int)(ratio[1]*(double)mView.getmRightBottomPosX());

                        int bottom = (int)(ratio[0]*(double)mView.getmRightBottomPosY());

                        savePhoto(mPreview.getPic(left,top,right,bottom));
                        mAutoFocus = true;
                    } 
                });
                tGetPic.start();
            }
            boolean pressed = false;
            if (!mTakePicture.isPressed()){
                pressed = true;
            }
        }      
    };

    // just to close the app and release resources.
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (keyCode == KeyEvent.KEYCODE_BACK){
            finish();
        }
        return super.onKeyDown(keyCode, event); 
    }

    private boolean savePhoto(Bitmap bm) {
        FileOutputStream image = null;
        try {
            image = new FileOutputStream(mLocation);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        bm.compress(CompressFormat.JPEG, 100, image);
        if (bm != null) {
            int h = bm.getHeight();
            int w = bm.getWidth();
            //Log.i(TAG, "savePhoto(): Bitmap WxH is " + w + "x" + h);
        } else {
            //Log.i(TAG, "savePhoto(): Bitmap is null..");
            return false;
        }
        return true;
    }

    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        boolean intercept = false;
        switch (action) {
        case MotionEvent.ACTION_UP:
            break;
        case MotionEvent.ACTION_DOWN:
            float x = ev.getX();
            float y = ev.getY();
            // here we intercept the button press and give it to this 
            // activity so the button press can happen and we can take 
            // a picture.
            if ((x >= rec.left) && (x <= rec.right) && (y>=rec.top) && (y<=rec.bottom)){
                intercept = true;
            }
            break;
        }
        return intercept;
    }

    // mainly used for autofocus to happen when the user takes a picture
    // I also use it to redraw the canvas using the invalidate() method
    // when I need to redraw things.
    public void onSensorChanged(SensorEvent event) {

        if (mInvalidate == true){
            mView.invalidate();
            mInvalidate = false;
        }
        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];
        if (!mInitialized){
            mLastX = x;
            mLastY = y;
            mLastZ = z;
            mInitialized = true;
        }
        float deltaX  = Math.abs(mLastX - x);
        float deltaY = Math.abs(mLastY - y);
        float deltaZ = Math.abs(mLastZ - z);

        if (deltaX > .5 && mAutoFocus){ //AUTOFOCUS (while it is not autofocusing)
            mAutoFocus = false;
            mPreview.setCameraFocus(myAutoFocusCallback);
        }
        if (deltaY > .5 && mAutoFocus){ //AUTOFOCUS (while it is not autofocusing)
            mAutoFocus = false;
            mPreview.setCameraFocus(myAutoFocusCallback);
        }
        if (deltaZ > .5 && mAutoFocus){ //AUTOFOCUS (while it is not autofocusing) */
            mAutoFocus = false;
            mPreview.setCameraFocus(myAutoFocusCallback);
        }

        mLastX = x;
        mLastY = y;
        mLastZ = z;

    }

    // extra overrides to better understand app lifecycle and assist debugging
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //Log.i(TAG, "onDestroy()");
    }

    @Override
    protected void onPause() {
        super.onPause();
        //Log.i(TAG, "onPause()");
        mSensorManager.unregisterListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, mAccel, SensorManager.SENSOR_DELAY_UI);
        //Log.i(TAG, "onResume()");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        //Log.i(TAG, "onRestart()");
    }

    @Override
    protected void onStop() {
        super.onStop();
        //Log.i(TAG, "onStop()");
    }

    @Override
    protected void onStart() {
        super.onStart();
        //Log.i(TAG, "onStart()");
    }

    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // TODO Auto-generated method stub

    }

CameraPreview:

class Preview extends SurfaceView implements SurfaceHolder.Callback {   

private SurfaceHolder mHolder;
private Camera mCamera;
private Camera.Parameters mParameters;
private byte[] mBuffer;

// this constructor used when requested as an XML resource
public Preview(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public Preview(Context context) {
    super(context);
    init();
}

public void init() {
    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = getHolder();
    mHolder.addCallback(this);
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public Bitmap getPic(int x, int y, int width, int height) {
    System.gc(); 
    Bitmap b = null;
    Size s = mParameters.getPreviewSize();

    YuvImage yuvimage = new YuvImage(mBuffer, ImageFormat.NV21, s.width, s.height, null);
    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
    yuvimage.compressToJpeg(new Rect(x, y, width, height), 100, outStream); // make JPG
    b = BitmapFactory.decodeByteArray(outStream.toByteArray(), 0, outStream.size()); // decode JPG
    if (b != null) {
        //Log.i(TAG, "getPic() WxH:" + b.getWidth() + "x" + b.getHeight());
    } else {
        //Log.i(TAG, "getPic(): Bitmap is null..");
    }
    yuvimage = null;
    outStream = null;
    System.gc();
    return b;
}

private void updateBufferSize() {
    mBuffer = null;
    System.gc();
    // prepare a buffer for copying preview data to
    int h = mCamera.getParameters().getPreviewSize().height;
    int w = mCamera.getParameters().getPreviewSize().width;
    int bitsPerPixel = ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat());
    mBuffer = new byte[w * h * bitsPerPixel / 8];
    //Log.i("surfaceCreated", "buffer length is " + mBuffer.length + " bytes");
}

public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, acquire the camera and tell it where to draw.
    try {
        mCamera = Camera.open(); // WARNING: without permission in Manifest.xml, crashes
    }
    catch (RuntimeException exception) {
        //Log.i(TAG, "Exception on Camera.open(): " + exception.toString());
        Toast.makeText(getContext(), "Camera broken, quitting :(",Toast.LENGTH_LONG).show();
        // TODO: exit program
    }

    try {
        mCamera.setPreviewDisplay(holder);
        updateBufferSize();
        mCamera.addCallbackBuffer(mBuffer); // where we'll store the image data
        mCamera.setPreviewCallbackWithBuffer(new PreviewCallback() {
            public synchronized void onPreviewFrame(byte[] data, Camera c) {

                if (mCamera != null) { // there was a race condition when onStop() was called..
                    mCamera.addCallbackBuffer(mBuffer); // it was consumed by the call, add it back
                }
            }
        });
    } catch (Exception exception) {
        //Log.e(TAG, "Exception trying to set preview");
        if (mCamera != null){
            mCamera.release();
            mCamera = null;
        }
        // TODO: add more exception handling logic here
    }
}

public void surfaceDestroyed(SurfaceHolder holder) {
    // Surface will be destroyed when we return, so stop the preview.
    // Because the CameraDevice object is not a shared resource, it's very
    // important to release it when the activity is paused.
    //Log.i(TAG,"SurfaceDestroyed being called");
    mCamera.stopPreview();
    mCamera.release();
    mCamera = null;
}

// FYI: not called for each frame of the camera preview
// gets called on my phone when keyboard is slid out
// requesting landscape orientation prevents this from being called as camera tilts
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    //Log.i(TAG, "Preview: surfaceChanged() - size now " + w + "x" + h);
    // Now that the size is known, set up the camera parameters and begin
    // the preview.
    try {
        mParameters = mCamera.getParameters();
        mParameters.set("orientation","landscape");
        for (Integer i : mParameters.getSupportedPreviewFormats()) {
            //Log.i(TAG, "supported preview format: " + i);
        } 

        List<Size> sizes = mParameters.getSupportedPreviewSizes();
        for (Size size : sizes) {
            //Log.i(TAG, "supported preview size: " + size.width + "x" + size.height);
        }
        mCamera.setParameters(mParameters); // apply the changes
    } catch (Exception e) {
        // older phone - doesn't support these calls
    }

    updateBufferSize(); // then use them to calculate

    Size p = mCamera.getParameters().getPreviewSize();
    //Log.i(TAG, "Preview: checking it was set: " + p.width + "x" + p.height); // DEBUG
    mCamera.startPreview();
}

public Parameters getCameraParameters(){
    return mCamera.getParameters();
}

public void setCameraFocus(AutoFocusCallback autoFocus){
    if (mCamera.getParameters().getFocusMode().equals(mCamera.getParameters().FOCUS_MODE_AUTO) ||
            mCamera.getParameters().getFocusMode().equals(mCamera.getParameters().FOCUS_MODE_MACRO)){
        mCamera.autoFocus(autoFocus);
    }
}

public void setFlash(boolean flash){
    if (flash){
        mParameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
        mCamera.setParameters(mParameters);
    }
    else{
        mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
        mCamera.setParameters(mParameters);
    }
}

}

预览:

public class TouchView extends View {

//private final String TAG = "TESTTESTTESTESTTESTESTEST";

private Drawable mLeftTopIcon;
private Drawable mRightTopIcon;
private Drawable mLeftBottomIcon;
private Drawable mRightBottomIcon;

private boolean mLeftTopBool = false;
private boolean mRightTopBool = false;
private boolean mLeftBottomBool = false;
private boolean mRightBottomBool = false;

// Starting positions of the bounding box

private float mLeftTopPosX = 30;
private float mLeftTopPosY = 120;

private float mRightTopPosX = 150;
private float mRightTopPosY = 120;

private float mLeftBottomPosX = 30;
private float mLeftBottomPosY = 200;

private float mRightBottomPosX = 150;
private float mRightBottomPosY = 200;
private float mPosX;
private float mPosY;

private float mLastTouchX;
private float mLastTouchY;

private Paint topLine;
private Paint bottomLine;
private Paint leftLine;
private Paint rightLine;

private Rect buttonRec;

private int mCenter;

private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;

// you can ignore this 
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;


public TouchView(Context context){
    super(context);
    init(context);
}

public TouchView(Context context, AttributeSet attrs){
    super (context,attrs);
    init(context);
}

public TouchView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

private void init(Context context) {

    // I need to create lines for the bouding box to connect

    topLine = new Paint();
    bottomLine = new Paint();
    leftLine = new Paint();
    rightLine = new Paint();

    setLineParameters(Color.WHITE,2);

    // Here I grab the image that will work as the corners of the bounding
    // box and set their positions.

    mLeftTopIcon = context.getResources().getDrawable(R.drawable.corners);

    mCenter = mLeftTopIcon.getMinimumHeight()/2;
    mLeftTopIcon.setBounds((int)mLeftTopPosX, (int)mLeftTopPosY,
            mLeftTopIcon.getIntrinsicWidth()+(int)mLeftTopPosX,
            mLeftTopIcon.getIntrinsicHeight()+(int)mLeftTopPosY);

    mRightTopIcon = context.getResources().getDrawable(R.drawable.corners);
    mRightTopIcon.setBounds((int)mRightTopPosX, (int)mRightTopPosY,
            mRightTopIcon.getIntrinsicWidth()+(int)mRightTopPosX,
            mRightTopIcon.getIntrinsicHeight()+(int)mRightTopPosY);

    mLeftBottomIcon = context.getResources().getDrawable(R.drawable.corners);
    mLeftBottomIcon.setBounds((int)mLeftBottomPosX, (int)mLeftBottomPosY,
            mLeftBottomIcon.getIntrinsicWidth()+(int)mLeftBottomPosX,
            mLeftBottomIcon.getIntrinsicHeight()+(int)mLeftBottomPosY);

    mRightBottomIcon = context.getResources().getDrawable(R.drawable.corners);
    mRightBottomIcon.setBounds((int)mRightBottomPosX, (int)mRightBottomPosY,
            mRightBottomIcon.getIntrinsicWidth()+(int)mRightBottomPosX,
            mRightBottomIcon.getIntrinsicHeight()+(int)mRightBottomPosY);
    // Create our ScaleGestureDetector
    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());

}

private void setLineParameters(int color, float width){

    topLine.setColor(color);
    topLine.setStrokeWidth(width);

    bottomLine.setColor(color);
    bottomLine.setStrokeWidth(width);

    leftLine.setColor(color);
    leftLine.setStrokeWidth(width);

    rightLine.setColor(color);
    rightLine.setStrokeWidth(width);

}

// Draws the bounding box on the canvas. Every time invalidate() is called
// this onDraw method is called.
public void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.save();

    canvas.drawLine(mLeftTopPosX+mCenter, mLeftTopPosY+mCenter,
            mRightTopPosX+mCenter, mRightTopPosY+mCenter, topLine);
    canvas.drawLine(mLeftBottomPosX+mCenter, mLeftBottomPosY+mCenter,
            mRightBottomPosX+mCenter, mRightBottomPosY+mCenter, bottomLine);
    canvas.drawLine(mLeftTopPosX+mCenter,mLeftTopPosY+mCenter,
            mLeftBottomPosX+mCenter,mLeftBottomPosY+mCenter,leftLine);
    canvas.drawLine(mRightTopPosX+mCenter,mRightTopPosY+mCenter,
            mRightBottomPosX+mCenter,mRightBottomPosY+mCenter,rightLine);


    mLeftTopIcon.setBounds((int)mLeftTopPosX, (int)mLeftTopPosY,
            mLeftTopIcon.getIntrinsicWidth()+(int)mLeftTopPosX,
            mLeftTopIcon.getIntrinsicHeight()+(int)mLeftTopPosY);

    mRightTopIcon.setBounds((int)mRightTopPosX, (int)mRightTopPosY,
            mRightTopIcon.getIntrinsicWidth()+(int)mRightTopPosX,
            mRightTopIcon.getIntrinsicHeight()+(int)mRightTopPosY);

    mLeftBottomIcon.setBounds((int)mLeftBottomPosX, (int)mLeftBottomPosY,
            mLeftBottomIcon.getIntrinsicWidth()+(int)mLeftBottomPosX,
            mLeftBottomIcon.getIntrinsicHeight()+(int)mLeftBottomPosY);

    mRightBottomIcon.setBounds((int)mRightBottomPosX, (int)mRightBottomPosY,
            mRightBottomIcon.getIntrinsicWidth()+(int)mRightBottomPosX,
            mRightBottomIcon.getIntrinsicHeight()+(int)mRightBottomPosY);


    mLeftTopIcon.draw(canvas);
    mRightTopIcon.draw(canvas);
    mLeftBottomIcon.draw(canvas);
    mRightBottomIcon.draw(canvas);
    canvas.restore();
}


public boolean onTouchEvent(MotionEvent ev) {
    final int action = ev.getAction();
    boolean intercept = true;

    switch (action) {

    case MotionEvent.ACTION_DOWN: {

        final float x = ev.getX();
        final float y = ev.getY();

        // in CameraPreview we have Rect rec. This is passed here to return
        // a false when the camera button is pressed so that this view ignores
        // the touch event.
        if ((x >= buttonRec.left) && (x <=buttonRec.right) && (y>=buttonRec.top) && (y<=buttonRec.bottom)){
            intercept = false;
            break;
        }

        // is explained below, when we get to this method.
        manhattanDistance(x,y);

        // Remember where we started
        mLastTouchX = x;
        mLastTouchY = y;
        mActivePointerId = ev.getPointerId(0);
        break;
    }

    case MotionEvent.ACTION_MOVE: {

        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
        final float x = ev.getX();
        final float y = ev.getY();
        //Log.i(TAG,"x: "+x);
        //Log.i(TAG,"y: "+y);

        // Only move if the ScaleGestureDetector isn't processing a gesture.
        // but we ignore here because we are not using ScaleGestureDetector.
        if (!mScaleDetector.isInProgress()) {
            final float dx = x - mLastTouchX;
            final float dy = y - mLastTouchY;

            mPosX += dx;
            mPosY += dy;

            invalidate();
        }

        // Calculate the distance moved
        final float dx = x - mLastTouchX;
        final float dy = y - mLastTouchY;


        // Move the object
        if (mPosX >= 0 && mPosX <=800){
            mPosX += dx;
        }
        if (mPosY >=0 && mPosY <= 480){
            mPosY += dy;
        }

        // while its being pressed n it does not overlap the bottom line or right line
        if (mLeftTopBool && ((y+mCenter*2) < mLeftBottomPosY) && ((x+mCenter*2) < mRightTopPosX)){
            if (dy != 0){
                mRightTopPosY = y;
            }
            if (dx != 0){
                mLeftBottomPosX = x;
            }
            mLeftTopPosX = x;//mPosX;
            mLeftTopPosY = y;//mPosY;
        }
        if (mRightTopBool && ((y+mCenter*2) < mRightBottomPosY) && (x > (mLeftTopPosX+mCenter*2))){
            if (dy != 0){
                mLeftTopPosY = y;
            }
            if (dx != 0){
                mRightBottomPosX = x;
            }
            mRightTopPosX = x;//mPosX;
            mRightTopPosY = y;//mPosY;
        }
        if (mLeftBottomBool && (y > (mLeftTopPosY+mCenter*2)) && ((x +mCenter*2) < mRightBottomPosX)){
            if (dx != 0){
                mLeftTopPosX = x;
            }
            if (dy != 0){
                mRightBottomPosY = y;
            }
            mLeftBottomPosX = x;
            mLeftBottomPosY = y;
        }
        if (mRightBottomBool && (y > (mLeftTopPosY+mCenter*2)) && (x > (mLeftBottomPosX+mCenter*2) )){
            if (dx != 0){
                mRightTopPosX = x;
            }
            if (dy != 0){
                mLeftBottomPosY = y;
            }
            mRightBottomPosX = x;
            mRightBottomPosY = y;
        }

        // Remember this touch position for the next move event
        mLastTouchX = x;
        mLastTouchY = y;

        // Invalidate to request a redraw
        invalidate();
        break;
    }
    case MotionEvent.ACTION_UP: {
        // when one of these is true, that means it can move when onDraw is called
        mLeftTopBool = false;
        mRightTopBool = false;
        mLeftBottomBool = false;
        mRightBottomBool = false;
        //mActivePointerId = INVALID_POINTER_ID;
        break;
    }

    case MotionEvent.ACTION_CANCEL: {
        mActivePointerId = INVALID_POINTER_ID;
        break;
    }

    case MotionEvent.ACTION_POINTER_UP: {
        // Extract the index of the pointer that left the touch sensor
        final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) 
        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
        final int pointerId = ev.getPointerId(pointerIndex);
        if (pointerId == mActivePointerId) {
            // This was our active pointer going up. Choose a new
            // active pointer and adjust accordingly.
            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mLastTouchX = ev.getX(newPointerIndex);
            mLastTouchY = ev.getY(newPointerIndex);
            mActivePointerId = ev.getPointerId(newPointerIndex);
        }
        break;
    }
    }
    return intercept;
}

// Where the screen is pressed, calculate the distance closest to one of the 4 corners
// so that it can get the pressed and moved. Only 1 at a time can be moved.
private void manhattanDistance(float x, float y) {

    double leftTopMan = Math.sqrt(Math.pow((Math.abs((double)x-(double)mLeftTopPosX)),2)
            + Math.pow((Math.abs((double)y-(double)mLeftTopPosY)),2));

    double rightTopMan = Math.sqrt(Math.pow((Math.abs((double)x-(double)mRightTopPosX)),2)
            + Math.pow((Math.abs((double)y-(double)mRightTopPosY)),2));

    double leftBottomMan = Math.sqrt(Math.pow((Math.abs((double)x-(double)mLeftBottomPosX)),2)
            + Math.pow((Math.abs((double)y-(double)mLeftBottomPosY)),2));

    double rightBottomMan = Math.sqrt(Math.pow((Math.abs((double)x-(double)mRightBottomPosX)),2)
            + Math.pow((Math.abs((double)y-(double)mRightBottomPosY)),2));

    //Log.i(TAG,"leftTopMan: "+leftTopMan);
    //Log.i(TAG,"RightTopMan: "+rightTopMan);

    if (leftTopMan < 50){
        mLeftTopBool = true;
        mRightTopBool = false;
        mLeftBottomBool = false;
        mRightBottomBool = false;
    }
    else if (rightTopMan < 50){
        mLeftTopBool = false;
        mRightTopBool = true;
        mLeftBottomBool = false;
        mRightBottomBool = false;
    }
    else if (leftBottomMan < 50){
        mLeftTopBool = false;
        mRightTopBool = false;
        mLeftBottomBool = true;
        mRightBottomBool = false;
    }
    else if (rightBottomMan < 50){
        mLeftTopBool = false;
        mRightTopBool = false;
        mLeftBottomBool = false;
        mRightBottomBool = true;
    }

}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        mScaleFactor *= detector.getScaleFactor();

        // Don't let the object get too small or too large.
        mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));

        invalidate();
        return true;
    }
}

public float getmLeftTopPosX(){
    return mLeftTopPosX;
}
public float getmLeftTopPosY(){
    return mLeftTopPosY;
}
public float getmRightTopPosX(){
    return mRightTopPosX;
}
public float getmRightTopPosY(){
    return mRightTopPosY;
}
public float getmLeftBottomPosX() {
    return mLeftBottomPosX;
}
public float getmLeftBottomPosY() {
    return mLeftBottomPosY;
}
public float getmRightBottomPosY() {
    return mRightBottomPosY;
}
public float getmRightBottomPosX() {
    return mRightBottomPosX;
}
public void setRec(Rect rec) {
    this.buttonRec = rec;
}

// calls the onDraw method, I used it in my app Translanguage OCR
// because I have a thread that needs to invalidate, or redraw
// you cannot call onDraw from a thread not the UI thread.
public void setInvalidate() {
    invalidate();

}

}

TouchView中:

    public class Wait {
  public static void oneSec() {
     try {
       Thread.currentThread().sleep(1000);
       }
     catch (InterruptedException e) {
       e.printStackTrace();
       }
     }  
  public static void manySec(long s) {
     try {
       Thread.currentThread().sleep(s * 1000);
       }
     catch (InterruptedException e) {
       e.printStackTrace();
       }
     }
}

}

等待:

var response=ec.getResponse()