-3

So I have a dialogue 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, automatically?

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 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 amount of seconds. Any solution is highly appreciated! I think I have to handle it in the surfaceChanged() method, but I really don't know how!

As asked, here is the, AnimatedViewContainer class:

public abstract class AnimatedViewContainer extends Example {

    Context mContext;
    int mAnimationDuration;
    int mAnimationDurationShort;
    LayoutInflater mLayoutInflater;
    ViewGroup mParentGroup;
    View[] mContainerViews;

    boolean hasBeenClicked = false;

    int mCurrentIndex;
    int mMaxNumItems;
    int mIndexVisibleItem;

    public AnimatedViewContainer(Context context, int maxNumItems) {
        super(context);

        mContext = context;
        mMaxNumItems = maxNumItems;
        mContainerViews = new View[mMaxNumItems];

        // Retrieve and cache the system's default "medium" animation time
        mAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);
        // and "short"
        mAnimationDurationShort = getResources().getInteger(android.R.integer.config_shortAnimTime);

        mCurrentIndex = 0;

        mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        //TODO: shouldn't be null, should be any ViewGroup with the right LayoutParams
        mParentGroup = null;
    }





    public abstract void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index);

    public boolean createView() {

        if (mCurrentIndex >= mMaxNumItems) {
            return false; // indicates to terminate the loop
        }


        // handle/execute the concrete definition of the view content defined by the child class
        onCreateViewContent(mLayoutInflater, mParentGroup, mContainerViews, mCurrentIndex);


        // only the first container view should be visible
        if (mCurrentIndex == 0) {
            mContainerViews[mCurrentIndex].setVisibility(View.VISIBLE);
            mIndexVisibleItem = mCurrentIndex;
        } else {
            mContainerViews[mCurrentIndex].setVisibility(View.GONE);
        }


        // if you click on the container view, show next container view with a crossfade animation
        mContainerViews[mCurrentIndex].setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                crossfade(true);
                hasBeenClicked = true;
            }
        });


        // add the container view to the FrameLayout
        addView(mContainerViews[mCurrentIndex]);


        mCurrentIndex++;

        return true;
    }


    public void crossfade(boolean manuallyClicked) {
        //only rotate when example is actually shown and at least one content item was created. This may also prevent NPEs due to incompletely loaded views.
        if(!this.isShown() || mCurrentIndex == 0)
            return;

        //when example was previously clicked, don't do anything
        if(!manuallyClicked && hasBeenClicked){
            hasBeenClicked = false;
            return;
        }

        int numTotalItems = mCurrentIndex;
        final int indexVisibleItem = mIndexVisibleItem;


        int nextIndex = indexVisibleItem + 1;

        if (nextIndex >= numTotalItems) {
            nextIndex = 0;
        }

        final boolean hasOnlyOneItem;
        if (numTotalItems == 1) {
            hasOnlyOneItem = true;
        } else {
            hasOnlyOneItem = false;
        }


        if (hasOnlyOneItem) { //there is only one item in the mContainerViews
            mContainerViews[indexVisibleItem].animate().alpha(0.5f).setDuration(mAnimationDurationShort).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mContainerViews[indexVisibleItem].animate().alpha(1f).setDuration(mAnimationDurationShort).setListener(null);
                }
            });
        } else {
            // Set the next view to 0% opacity but visible, so that it is visible (but fully transparent) during the animation.
            mContainerViews[nextIndex].setAlpha(0f);
            mContainerViews[nextIndex].setVisibility(View.VISIBLE);

            // Animate the next view to 100% opacity, and clear any animation
            // listener set on the view.
            mContainerViews[nextIndex].animate().alpha(1f).setDuration(mAnimationDuration).setListener(null);

            // Animate the current view to 0% opacity. After the animation ends,
            // set its visibility to GONE as an optimization step (it won't participate in layout passes, etc.)
            mContainerViews[indexVisibleItem].animate().alpha(0f).setDuration(mAnimationDuration).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mContainerViews[indexVisibleItem].setVisibility(View.GONE);
                }
            });
        }

        mIndexVisibleItem = nextIndex;
    }

    @Override
    public void cleanup() {

    }

}
Jishan
  • 1,654
  • 4
  • 28
  • 62

7 Answers7

2

I could find a solution to change camera in some seconds(But keep in mind as Alex Cohn said you can't change the camera in 2 seconds because, normally it takes more than 2 seconds to start preview and it depends on the device) by changing your code a little bit. please use below code and check.

Note: I have not implemented any orientation changes and taking picture functions, I Hope you have already developed those functions, in fact you have only asked for changing the camera automatically in some seconds.

I used dialog fragment to show the preview in a dialog. Here is the code for CameraExample

import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

/**
 * Created by Admin on 6/26/2017.
 */

public class CameraExample extends DialogFragment {
    private final static String TAG = "CameraExample";

    private Camera mCamera;
    private CameraPreview mPreview;
    private Context mContext;
    private View view;
    private int mCamId = 0;

    public CameraExample() {

        mPreview = null;
        mContext = getContext();

    }

    // 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, int cameraId) {
        // 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) {
                mCamera = getCameraInstance(cameraId);
                if (mCamera != null) {
                    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
                    Camera.getCameraInfo(cameraId, cameraInfo);
                    try {
                        //Create our Preview view and set it as the content of this LinearLayout View
                        mPreview = new CameraPreview(context, mCamera, cameraId);
                        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
                        mPreview.setLayoutParams(layoutParams);
                    } catch (RuntimeException e) {
                        Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
                    }
                }
            }
        }
    }

    private CountDownTimer countDownTimer;

    private void switchCam() {
        //10 seconds
        countDownTimer = new CountDownTimer(10000, 1000) {

            @Override
            public void onTick(long l) {
                System.out.println(l + " left");
            }

            @Override
            public void onFinish() {
                cleanup();
                startCam();
            }
        }.start();

    }


    private void startCam() {

        initCamera(getContext(), mCamId);
        FrameLayout previewFrame = (FrameLayout) view.findViewById(R.id.preview);
        previewFrame.removeAllViews();
        // Add preview for inflation
        previewFrame.addView(mPreview);

        mCamId = mCamId == 0 ? 1 : 0;

        switchCam();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        getDialog().getWindow().setGravity(Gravity.CENTER);
//        getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);


        view = inflater.inflate(R.layout.camera_fragment, container, false);
        startCam();
        return view;
    }

    @Override
    public void onPause() {
        super.onPause();
        cleanup();
        if (countDownTimer != null)
            countDownTimer.cancel();
    }

    @Override
    public void onStart() {
        super.onStart();
        getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    }

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

And also I had to change your preview class also. See below for the code.

import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.io.IOException;

/**
 * Created by Admin on 6/26/2017.
 */

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.
        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }
    }

    @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;
        }


    }
} 
Tharindu Welagedara
  • 2,660
  • 18
  • 27
  • Thanks a ton! I get this error: ` An error occurred while connecting to camera: 2, failed to connect to service` This what I finally changed to using your code: https://pastebin.com/PdcqRfUb – Jishan Jun 27 '17 at 18:48
  • @Jeet.Deir can you send me the error log please? Also can you show us what this AnimatedViewContainer class is? – Tharindu Welagedara Jun 28 '17 at 03:22
1

There is a double init bug in your class. I could have it running and see the camera switch from 0 to 1 and back, after 10 sec, after the following fix:

I removed call to initCamera() from the CameraExample constructor. Instead, I put there call to CreateView(). Alternatively, you can call CreateView(), which is a public method, from the place where you create new CameraExample(context, i).

Note that this refers to the code in dropbox, not what is posted in the question.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
0

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

Use a timer and call switchFacing() periodically every 2 seconds.

But be aware of:

This class was deprecated in API level 21. We recommend using the new android.hardware.camera2 API for new applications.

edit2: Here is the complete class ready to use.

//This class uses Camera1 API to be backwards compatible.

private static String TAG = "CameraManager";

private Context mContext = null;
private SurfaceView mPreview = null;
private SurfaceHolder mHolder = null;
private Camera mCamera = null;
private int mFrontFaceID = -1;
private int mBackFaceID = -1;
private int mActualFacingID = -1;

public CameraManager(Context context, SurfaceView preview) {
    mContext = context;
    mPreview = preview;
    mHolder = mPreview.getHolder();
    mHolder.addCallback(this);
}

//called in onCreate
public void init() {
    Camera.CameraInfo info = new Camera.CameraInfo();
    for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            mFrontFaceID = i;
        }
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            mBackFaceID = i;
        }
    }
    if (mActualFacingID == -1) {
        if (mFrontFaceID != -1) {
            mActualFacingID = mFrontFaceID;
        } else {
            mActualFacingID = mBackFaceID;
        }
    }
    //At least one one camera will be available because of manifest declaration
}

//called first on surface created
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();
    }
    setCameraDisplayOrientation();
    setBestSupportedSizes();
    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;
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    Log.i(TAG, "surfaceCreated()");
    start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    Log.i(TAG, "surfaceChanged()");
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    Log.i(TAG, "surfaceDestroyed()");
    stop();
}

private void setBestSupportedSizes() {
    if (mCamera == null) {
        return;
    }
    Camera.Parameters parameters = mCamera.getParameters();
    List<Point> pictureSizes=getSortedSizes(parameters.getSupportedPictureSizes());

    List<Point> previewSizes=getSortedSizes(parameters.getSupportedPreviewSizes());

    Point previewResult=null;
    for (Point size:previewSizes){
        float ratio = (float) size.y / size.x;
        if(Math.abs(ratio-4/(float)3)<0.05){ //Aspect ratio of 4/3 because otherwise the image scales to much.
            previewResult=size;
            break;
        }
    }
    Log.i(TAG,"preview: "+previewResult.x+"x"+previewResult.y);
    Point pictureResult=null;
    if(previewResult!=null){
        float previewRatio=(float)previewResult.y/previewResult.x;
        for (Point size:pictureSizes){
            float ratio = (float) size.y / size.x;
            if(Math.abs(previewRatio-ratio)<0.05){
                pictureResult=size;
                break;
            }
        }
    }
    Log.i(TAG,"preview: "+pictureResult.x+"x"+pictureResult.y);

    if(previewResult!=null && pictureResult!=null){
        Log.i(TAG,"best preview: "+previewResult.x+"x"+previewResult.y);
        Log.i(TAG, "best picture: " + pictureResult.x + "x" + pictureResult.y);
        parameters.setPreviewSize(previewResult.y, previewResult.x);
        parameters.setPictureSize(pictureResult.y, pictureResult.x);
        mCamera.setParameters(parameters);
        mPreview.setBackgroundColor(Color.TRANSPARENT); //in the case of errors needed
    }else{
        mCamera.stopPreview();
        mPreview.setBackgroundColor(Color.BLACK);
    }
}

private List<Point> getSortedSizes(List<Camera.Size> sizes) {
    ArrayList<Point> list = new ArrayList<>();

    for (Camera.Size size : sizes) {
        int height;
        int width;
        if (size.width > size.height) {
            height = size.width;
            width = size.height;
        } else {
            height = size.height;
            width = size.width;
        }
        list.add(new Point(width, height));

    }

    Collections.sort(list, new Comparator<Point>() {
        @Override
        public int compare(Point lhs, Point rhs) {
            long lhsCount = lhs.x * (long) lhs.y;
            long rhsCount = rhs.x * (long) rhs.y;
            if (lhsCount < rhsCount) {
                return 1;
            }
            if (lhsCount > rhsCount) {
                return -1;
            }
            return 0;
        }
    });
    return list;
}

//TAKE PICTURE
public void takePhoto() {
    if (mCamera != null) {
        mCamera.takePicture(null, null, this);
    }
}

@Override
public void onPictureTaken(byte[] data, Camera camera) {
    //do something with your picture
}

//ROTATION
private void setCameraDisplayOrientation() {
    if (mCamera != null) {
        mCamera.setDisplayOrientation(getRotation());
    }
}

public int getRotation() {
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(mActualFacingID, info);
    int rotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
            .getRotation();
    int degrees = 0;
    switch (rotation) {
        case Surface.ROTATION_0:
            degrees = 0;
            break;
        case Surface.ROTATION_90:
            degrees = 90;
            break;
        case Surface.ROTATION_180:
            degrees = 180;
            break;
        case Surface.ROTATION_270:
            degrees = 270;
            break;
    }

    int result;
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
        result = (info.orientation + degrees) % 360;
        result = (360 - result) % 360;  // compensate the mirror
    } else {  // back-facing
        result = (info.orientation - degrees + 360) % 360;
    }
    return result;
}

In some class call:

SurfaceView preview = (SurfaceView) findViewById(R.id.surfaceView);
CameraManager mgr = new CameraManager(MainActivity.this, MainActivity.this, preview);
mgr.init();
...
mgr.takePhoto(); //surface must already be created 
mgr.switchFacing();
mgr.takePhoto();

This code should support almost all devices. The most supported aspect ratio is 4:3, the code takes care of that.

edit3: The surface view must be in the xml of course

<SurfaceView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/surfaceView" />
Appyx
  • 1,145
  • 1
  • 12
  • 21
  • Can you show this in reference to the actual code I posted instead of a generic answer that you made? – Jishan Jun 18 '17 at 10:30
  • Just add as is? How to I make the switch in the MainClass? Thanks again! – Jishan Jun 18 '17 at 11:52
  • Yes, I don't know when you want to switch the cam, but just call the switchFacing-method when you want. – Appyx Jun 18 '17 at 12:09
  • Can you make the change in the `CameraPreview` Class and add it so I will mark it as an answer? – Jishan Jun 18 '17 at 19:57
  • Why would you want me to do this? This is just copy and paste. Are you getting any errors by using this code? – Appyx Jun 19 '17 at 09:21
  • I don't see how I use/define this `getCameraInstance(mActualFacingID);`. Can you please help me on that! – Jishan Jun 19 '17 at 19:54
  • 1
    mActualFacingID is an integer which is defined as a member variable. This id identifies the camera (front or back) You cannot have two instances the same time so you have to stop everything, get the right camera with the id and start everything agin. I edited my question to show you how to obtain these IDs. – Appyx Jun 19 '17 at 20:11
  • Any tips on how I call it from my classes? Just to be 100% sure? – Jishan Jun 19 '17 at 20:48
  • `ava.lang.NullPointerException: Attempt to invoke virtual method 'android.view.SurfaceHolder android.view.SurfaceView.getHolder()' on a null object reference at CameraPreview.(CameraPreview.java:36)` This is the error! – Jishan Jun 19 '17 at 21:05
  • Your preview has to be defined in xml and the id must match `surfaceView `in order to get a holder from that view. If the view ist null you cannot get a holder. – Appyx Jun 19 '17 at 21:08
  • your `SurfaceView` (mPreview) is null, that's the problem. see edited answer – Appyx Jun 19 '17 at 21:14
  • You can also create the surface view in code but this is far out of scope for the question^^ – Appyx Jun 19 '17 at 21:18
  • If it's the same error the view is still NULL. I don't understand why your findViewByID works ot of an activity... – Appyx Jun 19 '17 at 21:27
  • 1
    Why is this down voted? This is exactly what you need to do. I would recommend to to use a handler for Camera switches to make sure your changes are in sync. – Endre Börcsök Jun 23 '17 at 15:32
  • @EndreBörcsök you are right. It's a bad practice to call Camera.open() on the UI thread - this may cause ANR. It is important to open the camera [on a background Handler thread](https://stackoverflow.com/questions/18149964/best-use-of-handlerthread-over-other-similar-classes/19154438#19154438), otherwise all camera callbacks will happen in the UI thread, also resulting in occasional ANRs and other glitches. All this becomes even more important when the time to operate the camera is limited. – Alex Cohn Jun 26 '17 at 21:53
0

There is no way to switch the camera quickly. The time it takes to stop the camera, close it, open another camera, and start preview depends on the device, but in many cases (and sometimes on powerful modern devices) it will be more than 2 seconds that you put as your goal.

On the other hand, some Android devices support simultaneous operation of two cameras, see Is it possible to use front and back Camera at same time in Android and Android, Open Front and Back Cameras Simultaneously. So, on some Snapdragon 801 based devices, you can keep both cameras 'ready' and switch the video flow up to 30 times per second.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • I am fine with 2 seconds, but how does it even answer the question in anyway? – Jishan Jun 27 '17 at 18:10
  • let me understand better your requirement: you want to see on the screen 2 sec of front camera preview; black screen while the camera switches to rear-facing; 2 sec of rear preview; etc.? Or it is important to get a front picture again not later than 4 sec after the previous one, same for rear? – Alex Cohn Jun 28 '17 at 19:09
0

i think You should use this

mCamera= Camera.open(cameraId);

0 for CAMERA_FACING_BACK

1 for CAMERA_FACING_FRONT

for more reference flow this:-

https://developer.android.com/reference/android/hardware/Camera.html#open(int)

https://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#CAMERA_FACING_BACK

  • Please note that the camera Id used for Camera.open() is not one of the values defined for Camera.CameraInfo. You should use [Camera.CameraInfo.facing()](https://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#facing) method to check facing for each camera Id in range **0 ... [getNumberOfCameras()](https://developer.android.com/reference/android/hardware/Camera.html#getNumberOfCameras()) -1** – Alex Cohn Jul 01 '17 at 16:41
0

We can use threads to keep one camera active and let it stay for certain time. Swap camera and repaeat the same for infinite time.

private boolean isActive;

public void onStart(){
    super.onStart();
    isActive = true;
    continuousCameraChange(your_camera)
}

public void onResume(){
    super.onResume();
    isActive = true;
    continuousCameraChange(your_camera)
}

public void onPause(){
    super.onPause();
    isActive = false;
}


public void onDestroy(){
    super.onDestroy();
    isActive = false;
}


public void onStop(){
    super.onStop();
    isActive = false;
}

private void continuousCameraChange(Camera camera){
    do{
        switchCamera(camera);
    }while(isActive);
}

private void switchCamera(Camera camera){
    if (Camera.CameraInfo.facing == CAMERA_FACING_BACK){
        try{
            Thread.sleep(2000);
            camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
        }catch(InterruptedException ex){
            Thread.currentThread().interrupt();
        }
        //change your camera
        Camera.CameraInfo.facing == CAMERA_FACING_FRONT;
    }else{
        try{//change 2000 to change the time for which your camera stays available
            Thread.sleep(2000);
            camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
        }catch(InterruptedException ex){
            Thread.currentThread().interrupt();
        }
        //change your camera
        Camera.CameraInfo.facing == CAMERA_FACING_BACK;
    }
}
chinmish
  • 99
  • 1
  • 11
-1

I guess this is what you are looking for:

ImageButton useOtherCamera = (ImageButton) findViewById(R.id.useOtherCamera);
//if phone has only one camera, hide "switch camera" button
if(Camera.getNumberOfCameras() == 1){
useOtherCamera.setVisibility(View.INVISIBLE);
}
else {
useOtherCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (inPreview) {
    camera.stopPreview();
}
//NB: if you don't release the current camera before switching, you app will crash
camera.release();

//swap the id of the camera to be used
if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
    currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
else {
    currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
camera = Camera.open(currentCameraId);
//Code snippet for this method from somewhere on android developers, i forget where
setCameraDisplayOrientation(CameraActivity.this, currentCameraId, camera);
try {
    //this step is critical or preview on new camera will no know where to render to
    camera.setPreviewDisplay(previewHolder);
} catch (IOException e) {
    e.printStackTrace();
}
camera.startPreview();
}

This is a sample code where I am switching between front and back camera on the fly. Hope it will help.

Zohaib Hassan
  • 984
  • 2
  • 7
  • 11
  • 1
    Please note that the camera Id used for Camera.open() is not one of the values defined for Camera.CameraInfo. You should use [Camera.CameraInfo.facing()](https://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#facing) method to check facing for each camera Id in range **0 ... [getNumberOfCameras()](https://developer.android.com/reference/android/hardware/Camera.html#getNumberOfCameras()) -1** – Alex Cohn Jun 26 '17 at 08:38
  • Could you please define any drawbacks of using Camera Id? So that I can prevent using it. Because it's working fine with Camera Id. – Zohaib Hassan Jun 26 '17 at 20:57
  • One example is the Google Nexus Tablet (2012), which had one, front-facing camera. Its Id was 0. – Alex Cohn Jun 26 '17 at 22:23