Unable to Switch Front and Back Camera

So I have a dialog where I want to show the front and back camera previews sequentially, say after 2 seconds delay. Problem is, I can always set 1 camera view to the frame, how to I change it on the fly?

Here is where I want to change it on the fly:

public class CameraExample extends AnimatedViewContainer {

    private final static String TAG = "CameraExample";

    private Camera mCamera;
    private CameraPreview mPreview;
    private Context mContext;

    public CameraExample(Context context, int i) {
        super(context, i);

        mPreview = null;
        mContext = context;

        initCamera(mContext);

    }

    // A safe way to get an instance of the Camera object.
    public static Camera getCameraInstance(int cameraId) {
        Camera c = null;
        try {
            // attempt to get a Camera instance
            c = Camera.open(cameraId);
        } catch (Exception e) {
            // Camera is not available (in use or does not exist)
            Log.e(TAG, "CameraExample: " + "camera not available (in use or does not exist); " + e.getMessage());
        }
        return c; // returns null if camera is unavailable
    }

    private void initCamera(Context context) {

        // Check if this device has a camera
        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            // no camera on this device
            Log.e(TAG, "CameraExample: " + "this device has no camera");
        } else {
            // this device has a camera
            int numCameras = Camera.getNumberOfCameras();
            if (numCameras >= 0) {
                for (int cameraId = 0; cameraId < numCameras; cameraId++) {
                    mCamera = getCameraInstance(cameraId);
                    if (mCamera != null) {
                        CameraInfo cameraInfo = new CameraInfo();
                        Camera.getCameraInfo(cameraId, cameraInfo);
                        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
                            try {
                                //Create our Preview view and set it as the content of this LinearLayout View
                                mPreview = new CameraPreview(context, mCamera, cameraId);
                            } catch (RuntimeException e) {
                                Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
                            }
                        }
                        if (createView() == false) {
                            break;
                        }
                    }
                }
            }
        }
    }

    @Override
    public void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index) {
        containerViews[index] = layoutInflater.inflate(R.layout.example_camera, parentGroup, false);
        FrameLayout previewFrame = (FrameLayout) containerViews[index].findViewById(R.id.preview);

        // Add preview for inflation
        previewFrame.addView(mPreview);

    }

    @Override
    public void cleanup() {
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
}

The CameraPreview class:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

        private static final String TAG = "CameraPreview";

        private Context mContext;
        private SurfaceHolder mHolder;
        private Camera mCamera;
        private int mCameraId;

    public CameraPreview(Context context, Camera camera, int cameraId) {
        super(context);
        mContext = context;
        mCamera = camera;
        mCameraId = cameraId;

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

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.e(TAG, "CameraExample: " + "Error setting camera preview: " + e.getMessage());
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }
    }
}

I set my view here:

 @Override
    public void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index) {
        containerViews[index] = layoutInflater.inflate(R.layout.example_camera, parentGroup, false);
        FrameLayout previewFrame = (FrameLayout) containerViews[index].findViewById(R.id.preview);

        previewFrame.addView(mPreview);

    }

Problem is, I don't see how I can have 2 instances of the the 2 different cameras that a device generally has and change them automatically after certain seconds so that my frame displays the front and back camera preview one after other after every certain seconds.

Thanks for any help!

1 answer

  • answered 2017-06-17 19:57 Appyx

    You have to stop the camera, switch the facing and then start it again:

    public void start() {
        Log.i(TAG, "startCamera()");
        if (mCamera == null) {
            mCamera = getCameraInstance(mActualFacingID);
        }
        if (mCamera == null) {
            Log.i(TAG, "can't get camera instance");
            return;
        }
        try {
            mCamera.setPreviewDisplay(mHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // eventually set the size, position and orientation
        //setCameraDisplayOrientation();
        //setBestSupportedSizes();
        //setBestPreviewPosition();
        mCamera.startPreview();
    }
    
    public void stop() {
        Log.i(TAG, "stopCamera()");
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
    
    public void switchFacing() {
        if (mFrontFaceID == -1 || mBackFaceID == -1) {
            return;
        }
        stop();
        if (mActualFacingID == mFrontFaceID) {
            mActualFacingID = mBackFaceID;
        } else {
            mActualFacingID = mFrontFaceID;
        }
        start();
    }
    
    public Camera getCameraInstance(int cameraID) {
        Camera c = null;
        if (cameraID != -1) {
            try {
                c = Camera.open(cameraID);
            } catch (Exception e) {
                e.printStackTrace();
                Log.i(TAG, "error opening camera: " + cameraID);
            }
        }
        return c;
    }
    

    And then just call switchFacing() with a timer of 2 seconds.