Android Camera2 API switch back - front cameras - android

I'm creating a custom camera capturing videos with the new camera2 API.
My code is strongly inspired from the code provided by Google here. My camera preview has a button to switch from back to front camera and then from front to back camera.
The "camera preview" activity is launched with the back camera by default.
For some reason, when I click on the "switch/swap camera" button for the first time, it brings be to the front camera as it should, BUT everytime I click again, the switch/swap doesn't work anymore: the preview (on the front camera) fades a little bit, like if something is happening, but it remains on the currently selected (front) camera.
Here is my code :
In a RecordVideoFragment, in the onViewCreated:
// Switch camera button
switchCameraButton = (ImageButton) view.findViewById(R.id.button_switch_camera);
// Listener for Switch cameras button
switchCameraButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
switchCameras();
}
});
And here is the switchCameras() function:
private void switchCameras() {
mCameraOpenCloseLock.release();
mCameraDevice.close();
CameraManager mCameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
try {
String mCameraId = mCameraManager.getCameraIdList()[0];
if (mCameraId.equals("0")) { // If currently on FRONT camera (0 = CameraCharacteristics.LENS_FACING_FRONT)
mCameraId = "1"; // switch to BACK camera (1 = CameraCharacteristics.LENS_FACING_BACK)
switchCameraButton.setImageResource(R.drawable.ic_camera_front);
} else { // If currently on BACK camera
mCameraId = "0"; // switch to front camera
switchCameraButton.setImageResource(R.drawable.ic_camera_back);
}
try {
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) {
mCameraManager.openCamera(mCameraId, mStateCallback, null);
} else {
requestVideoPermissions();
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
} catch (CameraAccessException e) {
Toast.makeText(getActivity(), "Cannot access the camera.", Toast.LENGTH_SHORT).show();
getActivity().finish();
}
}
If you have any idea on what's happening that would save me. I have been bugging on this for days. Thank you very much

What you need to do is introduce new variables:
public static final String CAMERA_FRONT = "1";
public static final String CAMERA_BACK = "0";
private String cameraId = CAMERA_BACK;
remove cameraId local variable from openCamera method.
public void switchCamera() {
if (cameraId.equals(CAMERA_FRONT)) {
cameraId = CAMERA_BACK;
closeCamera();
reopenCamera();
switchCameraButton.setImageResource(R.drawable.ic_camera_front);
} else if (cameraId.equals(CAMERA_BACK)) {
cameraId = CAMERA_FRONT;
closeCamera();
reopenCamera();
switchCameraButton.setImageResource(R.drawable.ic_camera_back);
}
}
public void reopenCamera() {
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}

After looking at MrOnyszko answer i followed a slightly different approach:
In the Camera2Basic Tutorial a lens facing direction is used to set up the right camera, so i changed this direction before closing and reopening the camera.
private void switchCamera() {
if (mCameraLensFacingDirection == CameraCharacteristics.LENS_FACING_BACK) {
mCameraLensFacingDirection = CameraCharacteristics.LENS_FACING_FRONT;
closeCamera();
reopenCamera();
} else if (mCameraLensFacingDirection == CameraCharacteristics.LENS_FACING_FRONT) {
mCameraLensFacingDirection = CameraCharacteristics.LENS_FACING_BACK;
closeCamera();
reopenCamera();
}
}
private void reopenCamera() {
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
private void setUpCameraOutputs(int width, int height) {
Activity activity = getActivity();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing != mCameraLensFacingDirection) {
continue;
}
...

Related

Why does the front camera not open, when using Camera2 API?

I am using Camera2 API (https://github.com/googlearchive/android-Camera2Basic) for my project.
I want to use Front and Rear both camera, It’s working properly on my device
Realme5
Android: 10
But when I am trying to use front camera on
One Plus 6, Android: 10 or Samsung Galaxy J7 Nxt, Android 7.0 Or Redmi.
Then I am going on onConfigureFailed method and it’s redirect me firstActivity
Manifest ScreenShots:enter image description here
Log ScreenShots:enter image description here
Whole code in googlearchive GitHub link is given above
Variable Initialisation
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final int REQUEST_CAMERA_PERMISSION = 1;
private static final String FRAGMENT_DIALOG = "dialog";
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
public static int mSelectedFacing = 1;
flip camera button click
if (mTextureView.isAvailable()) {
if(mSelectedFacing ==0){
mSelectedFacing = 1;
}else {
mSelectedFacing = 0;
}
closeCamera();
openCamera(mTextureView.getWidth(), mTextureView.getHeight(), mSelectedFacing);
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
Open camera
private void openCamera(int width, int height,int mSelectedFacing) {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
requestCameraPermission();
return;
}
setUpCameraOutputs(width, height,mSelectedFacing);
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);
}
}
Close camera
private void closeCamera() {
try {
mCameraOpenCloseLock.acquire();
if (null != mCaptureSession) {
mCaptureSession.close();
mCaptureSession = null;
}
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
if (null != mImageReader) {
mImageReader.close();
mImageReader = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
mCameraOpenCloseLock.release();
}
}
CameraPreviewSession
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder
= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// Flash is automatically enabled when necessary.
setAutoFlash(mPreviewRequestBuilder);
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(
#NonNull CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
}, null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
Please help me …
Thanks in advance
I have do like it will capture image in background without any preview screen using Camera2 API in background service.
Visit https://codepalyers.blogspot.com/2020/12/capture-image-in-background-without.html
If you wish to use rear camera use
private final String frontCamera = "1";
private final String backCamera = "0";
as already define in code.

Camera2 MediaRecorder changes Frame Rate on Galaxy S9

I am not able to get a constant framerate with the camera2 API using MediaRecorder on the Galaxy S9 front camera.
Essentially I am using the example Project from https://github.com/googlesamples/android-Camera2Video but stripped it down to find the error. I removed the mTextureView and use only the mediaRecorder surface.
Here are the relevant code snippets:
#Override
protected void setUpMediaRecorder() throws IOException {
final Activity activity = getActivity();
if (null == activity) {
return;
}
// Camcorder Profile QUALITY_HIGH doenst work
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncodingBitRate(30000000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(2560, 1440);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mMediaRecorder.prepare();
}
#Override
protected void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
Range<Integer> range = getRange();
builder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, range);
}
// get highest range
private Range<Integer> getRange() {
CameraManager mCameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics chars = null;
try {
chars = mCameraManager.getCameraCharacteristics(mCameraManager.getCameraIdList()[1]);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Range<Integer>[] ranges = chars.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
Range<Integer> result = null;
for (Range<Integer> range : ranges) {
if (result == null) {
result = range;
} else {
int upper = range.getUpper();
int lower = range.getLower();
if (upper >= result.getUpper() && lower >= result.getLower()) {
result = range;
}
}
}
return result;
}
protected void startRecordingVideo() {
if (null == mCameraDevice) {
return;
}
try {
closeCaptureSession();
setUpMediaRecorder();
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
List<Surface> surfaces = new ArrayList<>();
// Set up Surface for the MediaRecorder
Surface recorderSurface = mMediaRecorder.getSurface();
surfaces.add(recorderSurface);
mPreviewBuilder.addTarget(recorderSurface);
// Start a capture session
// Once the session starts, we can update the UI and start recording
mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
mCaptureSession = cameraCaptureSession;
setUpCaptureRequestBuilder(mPreviewBuilder);
if (null == mCameraDevice) {
return;
}
try {
mCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
// UI
mButtonVideo.setText(R.string.stop);
mIsRecordingVideo = true;
// Start recording
mMediaRecorder.start();
}
});
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Activity activity = getActivity();
if (null != activity) {
Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
}
}
}, mBackgroundHandler);
} catch (CameraAccessException | IOException e) {
e.printStackTrace();
}
}
getRange() returns a Range of [30,30]. So it should record at 30fps. If I move the camera to some darker areas the frame rate suddenly drops. If locking the AE while moving to a light area the framerate is stable, even in dark areas.
So it seems to have something to do with AE but can not figure out what. Any help?

SurfaceView Camera App Switch Camera and Fix Dark Preview

I am building a camera app using surface view. The app loads the camera properly and image is captured. There are two scenarios in image capture:
The image is captured and nothing i.e bytes array is sent to the preview activity. It works fine here.
The image is captured and the byte array from picture callback is sent to the preview activity.
In the second scenario, the app shows a dark screen and becomes unresponsive. I don't believe I know the cause of this as I have checked with many tutorials and seen the same code.
Here's my code so far:
public class ImageActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private static final String TAG = ImageActivity.class.getSimpleName();
private ImageButton closeIV;
private ImageView flipCameraIV;
private FloatingActionButton fab_capture;
private LinearLayout galleryLayout;
private Camera camera;
private Camera.PictureCallback jpegCallback;
private SurfaceView surfaceView;
private SurfaceHolder holder;
private int currCamId = 0;
private boolean isGalleryImg = false;
private boolean isCameraImg = false;
private byte[] camBytes = null;
private static final int GAL_REQ_CODE = 240;
private static final int CAM_PERM_CODE = 242;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_image);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(getResources().getColor(R.color.black));
}
init();
holder = surfaceView.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
currCamId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
private void handleClicks() {
closeIV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
flipCameraIV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "Flip Clicked");
switchCamera();
}
});
galleryLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
isGalleryImg = true;
Log.d(TAG, "Gallery Button Clicked");
Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
galleryIntent.setType("image/*");
startActivityForResult(galleryIntent, GAL_REQ_CODE);
}
});
fab_capture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
captureImage();
}
});
jpegCallback = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] bytes, Camera camera) {
assert bytes != null;
Log.d(TAG, "Camera Bytes Array Length:\t" + bytes.length);
isCameraImg = true;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Intent intent = new Intent(ImageActivity.this, PreviewActivity.class);
intent.putExtra("camera_bytes", bytes);
intent.putExtra("fromCamera", isCameraImg);
startActivity(intent);
return;
//refreshCamera();
}
};
}
private void captureImage() {
camera.takePicture(null, null, jpegCallback);
}
public void refreshCamera() {
if (holder.getSurface() == null) {
return; // preview surface is empty
}
// stop preview, then make changes
try {
camera.stopPreview();
} catch (Exception ex) {
ex.printStackTrace();
}
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
private void init() {
closeIV = findViewById(R.id.closeIV);
fab_capture = findViewById(R.id.fab_capture);
galleryLayout = findViewById(R.id.galleryLayout);
flipCameraIV = findViewById(R.id.flipCameraIV);
surfaceView = findViewById(R.id.surfaceView);
handleClicks();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GAL_REQ_CODE && resultCode == RESULT_OK) {
Uri imgUri = data.getData();
Intent intent = new Intent(ImageActivity.this, PreviewActivity.class);
intent.putExtra("fromGallery", isGalleryImg);
intent.putExtra("gallery_image", imgUri.toString());
startActivity(intent);
}
}
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
for (int mResults : grantResults) {
if (mResults == PackageManager.PERMISSION_DENIED) {
requestPermissions(new String[]{Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
CAM_PERM_CODE);
} else {
Toast.makeText(ImageActivity.this, "Permission Already Granted", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
openCamera();
}
private void openCamera() {
try {
camera = Camera.open(currCamId);
} catch (RuntimeException rex) {
rex.printStackTrace();
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewFrameRate(20);
parameters.setPreviewSize(352, 288);
camera.setDisplayOrientation(90);
camera.setParameters(parameters);
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
refreshCamera();
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
camera.stopPreview();
camera.release();
camera = null;
}
#Override
protected void onPause() {
super.onPause();
camera.stopPreview();
}
#Override
protected void onDestroy() {
super.onDestroy();
if (camera != null){
camera.stopPreview();
camera.release();
camera = null;
}
}
}
Also, I have tried switching to the front camera and back again using this snippet but doesn't work.
private void switchCamera() {
// code I tried to switch camera with but not working
if (currCamId == Camera.CameraInfo.CAMERA_FACING_BACK){
currCamId = Camera.CameraInfo.CAMERA_FACING_FRONT;
} else {
currCamId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
camera = Camera.open(currCamId);
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, info);
int rotation = this.getWindowManager().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 rotate = (info.orientation - degrees + 360) % 360;
Camera.Parameters parameters = camera.getParameters();
parameters.setRotation(rotate);
try {
camera.setPreviewDisplay(surfaceView.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
camera.setParameters(parameters);
camera.setDisplayOrientation(90);
camera.startPreview();
//openCamera();
}
I need help in solving this. Thanks.
As i see you're trying to send picture as byte array which is not possible. Because there is a restriction for intent sizes since api23. When sending extras, you must think about the sizes of extras, it really destroys user experience and causes slow load for new activities.
Anyway, your byte array is sooo big with all that picture data and i think this causing an anr. What must you do? You must save that byte array as a jpeg file first, then just add filepath into your intent. Take a look to this solution
Oh and also, just a friendly advice based on experience, it's better to use a good camera library instead of android-sdk's classic usage. As i can say, worst part of android development is anything about medias, specially camera api. It's shaming when compared with ios and google is not doing any development about this lack, since 2015.

Unable to Switch Front and Back Camera

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() {
}
}
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;
}
}
}
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.
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" />
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.
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
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;
}
}
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.

android detect if other app try to open camera show alert dialoge

I want to create an application, and it needs to know when the camera is turned on by other app, whether the camera application is open or if a third party app is using the camera
how can i detect that if other app is try to open the camera . if other app try to open the camera i want to receive any broadcast before open the camera how can i do this.
i have also try this.
public boolean isCameraUsebyApp() {
Camera camera = null;
try {
camera = Camera.open();
} catch (RuntimeException e) {
return true;
} finally {
if (camera != null) camera.release();
}
return false;
}
but its alwys return true.
There is no broadcast for camera open or not but Camera Avaiability Listener in Camera2 Api, use below code
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
manager.registerAvailabilityCallback(new CameraManager.AvailabilityCallback() {
#Override
public void onCameraAvailable(String cameraId) {
super.onCameraAvailable(cameraId);
//Do your work
}
#Override
public void onCameraUnavailable(String cameraId) {
super.onCameraUnavailable(cameraId);
//Do your work
}
}, mHandler);
}
its only 21 and above
For below 21 you can use your code
public boolean isCameraInUse() {
Camera c = null;
try {
c = Camera.open();
} catch (RuntimeException e) {
return true;
} finally {
if (c != null) c.release();
}
return false;
}

Categories

Resources