Android SDK - camera2 - Draw rectangle over TextureView

aescript picture aescript · Jul 2, 2015 · Viewed 16k times · Source

Im new to android development, and I'm finding it hard to find good examples on the camera2 api.

Im working my way slowly through most issues, but on this one I am stuck. In the default camera, when you touch the screen to focus, it shows a rectangle of the focus area for a moment. I want to do something similar (Or in this case, the exact same thing to start off with so i can figure it out).

I read somewhere (I think the TextureView page in the SDK docs) that you cant draw on a textureview while its being used as a camera preview - and calling the lock method will return null rather than a canvas.

I found this online: https://github.com/commonsguy/vidtry/ But i cant get it to work. I either get errors saying my my main view cant be cast to my drawable view, or vice versa - Or my drawable view is on top and makes the screen black - Or its on the bottom and wont respond to touch events (and trying to force the performClick from the view above it casues crashes.)

Im stuck! Can anyone give me an explanation or example of how i can draw my rectangle over the event position for a few sconds?

Thanks!

Answer

Sahil Deswal picture Sahil Deswal · Jul 23, 2016
  1. First, for the camera2 api android example there is open source google sample code. https://github.com/googlesamples/android-Camera2Basic
  2. Second, for the part where you want to draw a rectangle(touch to focus), follow these steps -
    • Create a custom class extending SurfaceView.
    • Call the onTouchListener method in this custom class to detect finger coordinates and draw your rectangle using paint class in android. -Add this custom class above your TextureView that is displaying preview from camera2.
    • Turn the custom view transparent.
    • When you touch at some point on device screen then onTouchListener will be called which will draw on the canvas of custom view you added above you camera preview.
    • Finally, clear your canvas so you don't keep adding rectangles to the custom view since you only need one rect at one point of time.
    • Also, if not touched for some time the rectangle should disappear. Do this using a handler from custom view.

I am giving you some tested code to do this. I hope it helps you. BEST OF LUCK.

 private class CustomView extends SurfaceView {

    private final Paint paint;
    private final SurfaceHolder mHolder;
    private final Context context;

    public CustomView(Camera2BasicFragment context) {
        super(context.getActivity().getBaseContext());
        mHolder = getHolder();
        mHolder.setFormat(PixelFormat.TRANSPARENT);
        this.context = context.getActivity().getBaseContext();
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            invalidate();
            if (mHolder.getSurface().isValid()) {
                final Canvas canvas = mHolder.lockCanvas();
                Log.d("touch", "touchReceived by camera");
                if (canvas != null) {
                    Log.d("touch", "touchReceived CANVAS STILL Not Null");
                    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                    canvas.drawColor(Color.TRANSPARENT);
                    canvas.drawCircle(event.getX(), event.getY(), 100, paint);
                    mHolder.unlockCanvasAndPost(canvas);
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            Canvas canvas1 = mHolder.lockCanvas();
                            if(canvas1 !=null){
                                canvas1.drawColor(0, PorterDuff.Mode.CLEAR);
                                mHolder.unlockCanvasAndPost(canvas1);
                            }

                        }
                    }, 1000);

                }
                mHolder.unlockCanvasAndPost(canvas);
            }
        }

        return false;
    }
}