0
votes

I am creating custom camera using Camera2 API. I want to reopen camera after save the image using camera preview (Continue capture image). I have tried to reopen camera after save image but it's showing error.

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

private final TextureView.SurfaceTextureListener mSurfaceTextureListener
        = new TextureView.SurfaceTextureListener() {

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
        openCamera(width, height);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
        configureTransform(width, height);
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture texture) {
    }

};

Open camera Method

private void openCamera(int width, int height) {
        if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            requestCameraPermission();
            return;
        }
        setUpCameraOutputs(width, height);
        configureTransform(width, height);
        Activity activity = getActivity();
        CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        try {
            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                throw new RuntimeException("Time out waiting to lock camera opening.");
            }
            manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
        }
    }

Reopen camera Method

 public void reopenCamera() {
    Log.d("REOPENCAMERA", "reopenCamera: called.");
    if (mTextureView.isAvailable()) {
        Log.d(TAG, "reopenCamera: a surface is available.");
        if(stillCapturedImage){
            capture++;
            changeFrame(capture);
            openCamera(mTextureView.getWidth(), mTextureView.getHeight());
        }else{
            openCamera(mTextureView.getWidth(), mTextureView.getHeight());
        }
    } else {
        Log.d(TAG, "reopenCamera: no surface is available.");
        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
    }

}

Capture Session

private CameraCaptureSession.CaptureCallback mCaptureCallback
        = new CameraCaptureSession.CaptureCallback() {

    private void process(CaptureResult result) {
        switch (mState) {
            case STATE_PREVIEW: {
                // We have nothing to do when the camera preview is working normally.
                break;
            }
            case STATE_WAITING_LOCK: {
                Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                if (afState == null) {
                    captureStillPicture();
                } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
                        CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
                    // CONTROL_AE_STATE can be null on some devices
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null ||
                            aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                        mState = STATE_PICTURE_TAKEN;
                        captureStillPicture();
                    } else {
                        runPrecaptureSequence();
                    }
                }
                else if(afState == CaptureResult.CONTROL_AF_STATE_INACTIVE){
                    mState = STATE_PICTURE_TAKEN;
                    captureStillPicture();
                }
                break;
            }
            case STATE_WAITING_PRECAPTURE: {
                // CONTROL_AE_STATE can be null on some devices
                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState == null ||
                        aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
                        aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
                    mState = STATE_WAITING_NON_PRECAPTURE;
                }
                break;
            }
            case STATE_WAITING_NON_PRECAPTURE: {
                // CONTROL_AE_STATE can be null on some devices
                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                    mState = STATE_PICTURE_TAKEN;
                    captureStillPicture();
                }
                break;
            }
        }
    }

    @Override
    public void onCaptureProgressed(@NonNull CameraCaptureSession session,
                                    @NonNull CaptureRequest request,
                                    @NonNull CaptureResult partialResult) {
        process(partialResult);
    }

    @Override
    public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                   @NonNull CaptureRequest request,
                                   @NonNull TotalCaptureResult result) {
        process(result);
    }

};

Save Image Method

 private void saveTempImageToStorage(){
    Log.d(TAG, "saveTempImageToStorage: saving temp image to disk.");
    final ICallback callback = new ICallback() {
        @Override
        public void done(Exception e) {
            if(e == null){
                Log.d(TAG, "onImageSavedCallback: image saved!");
                mBackgroundImageRotater = new BackgroundImageRotater(getActivity());
                mBackgroundImageRotater.execute();
                mIsImageAvailable = true;
                mCapturedImage.close();
            }
            else{
                Log.d(TAG, "onImageSavedCallback: error saving image: " + e.getMessage());
                showSnackBar("Error displaying image", Snackbar.LENGTH_SHORT);
            }
        }
    };

    ImageSaver imageSaver = new ImageSaver(
            mCapturedImage,
            getActivity().getExternalFilesDir(null),
            callback
    );
    mBackgroundHandler.post(imageSaver);
}
1
from where are you calling the reopenCamera method ? - Wasim Ansari

1 Answers

0
votes

The reopenCamera method should be just fine, but you will need to move some of your background task, which is updating your UI, to the main thread.

The sample code :

runOnUiThread(new Runnable() {

    @Override
    public void run() {

        // The code which updates your UI

    }
});

At last, please make sure that you are correctly working with the lifecycle methods.

You can find more via official documentation