I am building a camera app using surface view and it worked fine after few tests then subsequent tests saw the app crashing with this exception in logcat:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.hardware.Camera$Parameters android.hardware.Camera.getParameters()' on a null object reference
at com.jjoey.envisionocr.MainActivity.setCameraFocus(MainActivity.java:102)
at com.jjoey.envisionocr.MainActivity.startCamera(MainActivity.java:54)
at com.jjoey.envisionocr.MainActivity.checkPerms(MainActivity.java:69)
at com.jjoey.envisionocr.MainActivity.onCreate(MainActivity.java:37)
at android.app.Activity.performCreate(Activity.java:6671)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
This happens on this line number in code: Camera.Parameters parameters = camera.getParameters(); I have called Camera.open(id) with the id set to back camera.
Here's my activity code:
public class MainActivity extends AppCompatActivity {
private FrameLayout frameLayout; //camera surface container
private ImageView captureImgBtn;
private Camera camera;
private CameraPreview preview;
private int type = 0;
public static final int REQ_CAMERA = 102;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPerms();
initViews();
// startCamera();
captureImgBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
camera.takePicture(mShutterCallback, null, mPictureCallback);
}
});
}
private void startCamera() {
if (checkCameraHardware()){
setCameraFocus();
camera = getCameraInstance(type);
preview = new CameraPreview(this, camera, type);
frameLayout.addView(preview);
} else {
Toast.makeText(getApplicationContext(), "Device not support camera feature", Toast.LENGTH_SHORT).show();
}
}
private void checkPerms() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
askPerms();
} else {
startCamera();
}
}
private void askPerms() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQ_CAMERA);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case REQ_CAMERA:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
startCamera();
} else {
finish();
}
break;
}
}
private void releaseCameraAndPreview() {
if (camera != null) {
camera.release();
camera = null;
}
}
private void setCameraFocus() {
releaseCameraAndPreview();
Camera.Parameters parameters = camera.getParameters();
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)){
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
camera.setParameters(parameters);
}
private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
#Override
public void onShutter() {
// do ntn
}
};
private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] bytes, Camera camera) {
}
};
private Camera getCameraInstance(int type) {
Camera cam = null;
try {
cam = Camera.open(type);
} catch (Exception e){
Log.d("tag", "Error setting camera not open " + e);
e.printStackTrace();
}
return cam;
}
private boolean checkCameraHardware() {
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
return true;
} else {
return false;
}
}
private void initViews() {
frameLayout = (FrameLayout) findViewById(R.id.frameCamera);
captureImgBtn = findViewById(R.id.captureImgBtn);
}
}
I have created the CameraPreview class like this:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private Context context;
private SurfaceHolder holder;
private Camera camera;
private int cameraType;
public CameraPreview(Context context, Camera camera, int cameraType) {
super(context);
this.context = context;
this.camera = camera;
this.cameraType = cameraType;
holder = getHolder();
holder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
camera.setPreviewDisplay(surfaceHolder);
setCameraDisplayOrientation((Activity) context, cameraType, camera);
camera.startPreview();
} catch (IOException e) {
Log.d("tag", "Error setting camera preview: " + e.getMessage());
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
if (holder == null)
return;
try {
camera.stopPreview();
camera.setPreviewDisplay(surfaceHolder);
setCameraDisplayOrientation((Activity) context, cameraType, camera);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.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 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;
}
camera.setDisplayOrientation(result);
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
camera.release();
}
}
Does anyone know why this error is coming up and how to solve it? I have tried this method to release the camera before opening it like below:
private void releaseCameraAndPreview() {
if (camera != null) {
camera.release();
camera = null;
}
}
but it doesn't seem to be the solution. Any help would be appreciated. Thanks.
The call to releaseCameraAndPreview() is setting the camera object to null. So when you call camera.getParameters() you are trying to invoke a method on a null.
Related
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.
I want to capture image previewed in surfaceView.Capturing time is every 42 millisecond.While capturing I want to send these images to the server as byteArray at this moment.For security reason, photo cant is saved to sd.I must use this for making a video call.Can anyone help me?Pls
Button take;
Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
Camera.PictureCallback jpegCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPermission();
surfaceView = (SurfaceView) findViewById(R.id.surface);
surfaceHolder = surfaceView.getHolder();
take = (Button) findViewById(R.id.take);
take.setOnClickListener(this);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
surfaceHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
jpegCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.d("Log", "onPictureTaken - wrote bytes: " + data.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
Toast.makeText(getApplicationContext(), "Picture Saved", Toast.LENGTH_SHORT).show();
refreshCamera();
}
};
}
public void captureImage() throws IOException {
//take the picture
camera.takePicture(null, null, jpegCallback);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
// open the camera
camera = Camera.open();
} catch (RuntimeException e) {
// check for exceptions
System.err.println(e);
return;
}
Camera.Parameters param;
param = camera.getParameters();
// modify parameter
List<Camera.Size> sizes = param.getSupportedPreviewSizes();
Camera.Size selected = sizes.get(0);
param.setPreviewSize(selected.width,selected.height);
camera.setParameters(param);
try {
// The Surface has been created, now tell the camera where to draw
// the preview.
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
// check for exceptions
System.err.println(e);
return;
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
refreshCamera();
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
// stop preview and release camera
camera.stopPreview();
camera.release();
camera = null;
}
public void refreshCamera() {
if (surfaceHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
}
}
private void requestPermission() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
}
private boolean checkPermission() {
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
if (result == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
}
break;
}
}
#Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.take:{
try {
captureImage();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
So while previewing in SurfaceView I must get every 42 millis photo as byteArray and send it
I found solution to my problem. I have fixed it through setPreviewCallbackWithBuffer an onPreviewFrame.There is no need neither handler nor timer...
private Camera camera;
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private ImageView endCallBtn;
private ImageView micBtn;
private ImageView visibilityBtn;
private ImageView cameraBtn;
private Boolean clickedForMic = false;
private Boolean clickedForCamera = false;
private Boolean clickedForVisiblity = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_call);
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
if (Build.VERSION.SDK_INT >= 23) {
if (checkPermission()) {
Log.e("permission", "Permission already granted.");
} else {
requestPermission();
}
}
endCallBtn = (ImageView) findViewById(R.id.endCallBtn);
endCallBtn.setOnClickListener(this);
micBtn = (ImageView) findViewById(R.id.micBtn);
micBtn.setImageResource(R.drawable.ic_mic_white_48px);
micBtn.setOnClickListener(this);
visibilityBtn = (ImageView) findViewById(R.id.visibilityBtn);
visibilityBtn.setImageResource(R.drawable.ic_visibility_white_48px);
visibilityBtn.setOnClickListener(this);
cameraBtn = (ImageView) findViewById(R.id.cameraBtn);
cameraBtn.setImageResource(R.drawable.ic_camera_rear_white_48px);
cameraBtn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.cameraBtn: {
if (clickedForCamera == false) {
if (clickedForVisiblity == true) {
Toast.makeText(VideoCallActivity.this, "Видимость камеры заблокирована", Toast.LENGTH_SHORT).show();
} else {
stopCamera();
startCameraBack();
cameraBtn.setImageResource(R.drawable.ic_camera_front_white_48px);
clickedForCamera = true;
}
} else {
if (clickedForVisiblity == true) {
Toast.makeText(VideoCallActivity.this, "Видимость камеры заблокирована", Toast.LENGTH_SHORT).show();
} else {
stopCamera();
startCameraFront();
cameraBtn.setImageResource(R.drawable.ic_camera_rear_white_48px);
clickedForCamera = false;
}
}
break;
}
case R.id.micBtn: {
if (clickedForMic == false) {
micBtn.setImageResource(R.drawable.ic_mic_off_white_48px);
micBtn.setColorFilter(Color.parseColor("#00897B"));
clickedForMic = true;
} else {
micBtn.setImageResource(R.drawable.ic_mic_white_48px);
micBtn.setColorFilter(Color.parseColor("#ffffff"));
clickedForMic = false;
}
break;
}
case R.id.endCallBtn: {
stopCamera();
finish();
overridePendingTransition(R.anim.window3, R.anim.window4);
break;
}
case R.id.visibilityBtn: {
if (clickedForVisiblity == false) {
camera.stopPreview();
visibilityBtn.setImageResource(R.drawable.ic_visibility_off_white_48px);
visibilityBtn.setColorFilter(Color.parseColor("#00897B"));
clickedForVisiblity = true;
} else {
camera.startPreview();
visibilityBtn.setImageResource(R.drawable.ic_visibility_white_48px);
visibilityBtn.setColorFilter(Color.parseColor("#ffffff"));
clickedForVisiblity = false;
}
break;
}
}
}
private void requestPermission() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
}
private boolean checkPermission() {
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
if (result == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
}
break;
}
}
private void stopCamera() {
camera.stopPreview();
camera.release();
}
private void startCameraFront() {
if (checkPermission()) {
try {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
} catch (Exception e) {
return;
}
Camera.Parameters param;
camera.setDisplayOrientation(90);
param = camera.getParameters();
param.setPreviewFrameRate(24);
param.setPreviewFpsRange(22000, 30000);
camera.setParameters(param);
try {
camera.setPreviewDisplay(surfaceHolder);
} catch (Exception e) {
return;
}
Log.v("CameraTest", "Camera PreviewFrameRate = " + camera.getParameters().getPreviewFrameRate());
Camera.Size previewSize = camera.getParameters().getPreviewSize();
int dataBufferSize = (int) (previewSize.height * previewSize.width *
(ImageFormat.getBitsPerPixel(camera.getParameters().getPreviewFormat()) / 8.0));
camera.addCallbackBuffer(new byte[dataBufferSize]);
camera.addCallbackBuffer(new byte[dataBufferSize]);
camera.addCallbackBuffer(new byte[dataBufferSize]);
camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
private long timestamp = 0;
public synchronized void onPreviewFrame(byte[] data, Camera camera) {
//Log.v("CameraTest", "Time Gap = " + (System.currentTimeMillis() - timestamp));
Log.v("CameraTest", " data: " + String.valueOf(data.length));
timestamp = System.currentTimeMillis();
try {
camera.addCallbackBuffer(data);
} catch (Exception e) {
Log.e("CameraTest", "addCallbackBuffer error");
return;
}
return;
}
});
camera.startPreview();
}
}
private void startCameraBack() {
if (checkPermission()) {
try {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
} catch (Exception e) {
return;
}
Camera.Parameters param;
camera.setDisplayOrientation(90);
param = camera.getParameters();
//modify parameter
param.setPreviewFrameRate(30);
camera.setParameters(param);
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
Log.d("Problema", e.toString());
return;
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
startCameraFront();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
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.
I know there are some similar subjects connecting to this but I couldn't solve mine. anyway,I am trying to make some front camera with "flash" where I am calling Camera.release only once in the whole activities, when surfaceDestroyed(). so here is my MainActivity:
#SuppressWarnings("deprecation")
public class MainActivity extends AppCompatActivity {
private Camera mCamera = null;
private CameraPreview mCameraView = null;
private int cameraId = 0;
private void addView() {
if (!getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG)
.show();
} else {
cameraId = findFrontFacingCamera();
if (cameraId < 0) {
Toast.makeText(this, "No front facing camera found.",
Toast.LENGTH_LONG).show();
} else {
try {
mCamera = Camera.open(cameraId);
} catch (Exception e) {
Log.d("ERROR", "Failed to get camera: " + e.getMessage());
}
}
}
if (mCamera != null) {
mCameraView = new CameraPreview(this, mCamera);//create a SurfaceView to show camera data
FrameLayout camera_view = (FrameLayout) findViewById(R.id.camera_view);
camera_view.addView(mCameraView);//add the SurfaceView to the layout
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addView();
ImageButton imgCapture = (ImageButton) findViewById(R.id.imgCapture);
imgCapture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
WindowManager.LayoutParams layout = getWindow().getAttributes();
layout.screenBrightness = 1F;
getWindow().setAttributes(layout);
setContentView(R.layout.whitescreen);
new CountDownTimer(3000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
if (CameraPreview.safeToTakePicture) {
CameraPreview.safeToTakePicture = false;
mCamera.takePicture(null, null,
new PhotoHandler(getApplicationContext()));
}
setContentView(R.layout.activity_main);
addView();
}
}.start();
}
});
}
private int findFrontFacingCamera() {
int cameraId = -1;
// Search for the front facing camera
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
Log.d("Camera", "Camera found");
cameraId = i;
break;
}
}
return cameraId;
}
}
When pressing the capture button I switch the layout to an empty one(white layout), wait 3 seconds take a picture and then add the camera view again, here is my CameraPreview class:
#SuppressWarnings("deprecation")
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public static boolean safeToTakePicture = false;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mCamera.setDisplayOrientation(90);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("ERROR", "Camera error on surfaceCreated " + e.getMessage());
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
if (mHolder.getSurface() == null)
return;
try {
mCamera.stopPreview();
} catch (Exception e) {
Log.d("ERROR", "Trying the camera and it's not running");
}
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
safeToTakePicture = true;
} catch (IOException e) {
Log.d("ERROR", "Camera error on surfaceChanged " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mCamera.stopPreview();
mCamera.release();
}
}
I get the error Camera is being used after Camera.release was called a lot of times, for example when taking a picture:
07-02 14:49:35.561 19017-19017/davidandguy.com.selfielightcamera E/AndroidRuntime: FATAL EXCEPTION: main
Process: davidandguy.com.selfielightcamera, PID: 19017
java.lang.RuntimeException: Camera is being used after Camera.release() was called
at android.hardware.Camera.native_takePicture(Native Method)
at android.hardware.Camera.takePicture(Camera.java:1523)
at android.hardware.Camera.takePicture(Camera.java:1468)
at davidandguy.com.selfielightcamera.MainActivity$1$1.onFinish(MainActivity.java:65)
at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:127)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Or even when onResume() is called, for example, minimize the activity and then run again. I know I need to put somewhere onPause() and onResume() but I don't know where/how to implement it. thanks
This is really overdue but as I managed to solve a similar problem of mine a minute ago, I thought I'd contribute for the benefit of yourself and anyone else who might be desperately searching Stack.
I cant see your lifecycle code here , but heres what worked for me, surfaceDestroyed was empty in my case
Firstly, the cameraPreview
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
try {
this.mCamera.setPreviewDisplay(surfaceHolder);
this.mCamera.startPreview();
} catch (Exception e) {
}
}
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
//TODO we need this here too because on SurfaceCreated we always need to open the camera, in case its released
this.mCamera.setPreviewDisplay(surfaceHolder);
this.mCamera.setDisplayOrientation(90);
//this.mCamera.startPreview();
} catch (IOException e) {
}
}
Next, the CameraActivity
#Override
public void onResume() {
super.onResume();
try{
mCamera = openFrontFacingCameraGingerbread();
// Add to Framelayout
this.mCameraPreview = new CameraPreview(this, this.mCamera);
mImage.removeAllViews();
this.mImage.addView(this.mCameraPreview);
}catch (RuntimeException ex){
}
}
#Override
public void onPause() {
super.onPause();
captureButton.setText("Begin Capture");
if(CameraActivity.this.timer !=null) {
CameraActivity.this.timer.cancel();
CameraActivity.this.timer.purge();
CameraActivity.this.timer = null;
}
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCameraPreview.getHolder().removeCallback(mCameraPreview);
mCamera.release();
mCamera = null;
}
}
#Override
protected void onDestroy(){
super.onDestroy();
releaseCameraAndPreview();
}
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
if(mCameraPreview != null){
mCameraPreview.destroyDrawingCache();
mCameraPreview.mCamera = null;
}
}
I am using camera in my application,I have no done more work on camera my requirement is only taken picture and with front and back camera and flash light.Camera will be open inside a customview for that I am using this code:-
public class CaptureDealImage extends Activity implements OnClickListener,
CameraCallback {
private Camera myCamera;
private MyCameraSurfaceView myCameraSurfaceView;
private MediaRecorder mediaRecorder;
private Button objbtncapture, objbtnback, objbtngalary, objbtnretake,
objbtnuse;
private Button objbtnflashlight, objbbtnfrontcam;// ,flashButton_p,flashButton_l,cameraRotate_p,cameraRotate_l;
private boolean recording;
private TextView show_p, show_l;
int nCurrentOrientation;
private WakeLock wakeLock;
private int count, mode;
private boolean backendCamera = true;
private FrameLayout mymiddlelayout;
private String sdcardpath;
private boolean flashlight = false;
private boolean cameramode = false;
private boolean isfrontcamera = false;
private RelativeLayout objrelativeLayoutretake, objrelativeLayout3;
private byte[] data;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dealpick);
PowerManager mgr = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = mgr
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
// Get Camera for preview
objbtnflashlight = (Button) findViewById(R.id.btnflashlight);
objbbtnfrontcam = (Button) findViewById(R.id.bbtnfrontcam);
objbtncapture = (Button) findViewById(R.id.btncapture);
objbtngalary = (Button) findViewById(R.id.btngalary);
objbtnback = (Button) findViewById(R.id.btnback);
objbtnretake = (Button) findViewById(R.id.btnretake);
objbtnuse = (Button) findViewById(R.id.btnuse);
objrelativeLayoutretake = (RelativeLayout) findViewById(R.id.relativeLayoutretake);
objrelativeLayout3 = (RelativeLayout) findViewById(R.id.relativeLayout3);
objbtnback.setOnClickListener(this);
objbtncapture.setOnClickListener(this);
objbtngalary.setOnClickListener(this);
objbtnflashlight.setOnClickListener(this);
objbbtnfrontcam.setOnClickListener(this);
objbtnretake.setOnClickListener(this);
objbtnuse.setOnClickListener(this);
}
private Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
Display getOrient = getWindowManager().getDefaultDisplay();
if (getOrient.getHeight() > getOrient.getWidth()) {
c.setDisplayOrientation(90);
}
} catch (Exception e) {
}
return c; // returns null if camera is unavailable
}
#Override
protected void onPause() {
super.onPause();
releaseCamera();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
myCamera = getCameraInstance();
if (myCamera == null) {
Toast.makeText(CaptureDealImage.this, "Fail to get Camera",
Toast.LENGTH_LONG).show();
}
myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
mymiddlelayout = (FrameLayout) findViewById(R.id.middlelayout);
mymiddlelayout.removeAllViews();
mymiddlelayout.addView(myCameraSurfaceView);
myCameraSurfaceView.setCallback(this);
}
private void releaseCamera() {
/*
* if (myCamera != null) { myCamera.release(); // release the camera for
* other applications myCamera = null; }
*/
Camera camera = this.myCameraSurfaceView.getCamera();
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
wakeLock.release();
/*
* ReleaseRootBitmap mReleaseRootBitmap=new ReleaseRootBitmap();
* LinearLayout
* mLinearLayout=(LinearLayout)findViewById(R.id.record_video_parent);
* mReleaseRootBitmap.unbindDrawables(mLinearLayout);
*/
}
public class MyCameraSurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private CameraCallback callback = null;
private boolean isStarted = true;
public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
initialize(context);
}
public MyCameraSurfaceView(Context context) {
super(context);
initialize(context);
}
public void setCallback(CameraCallback callback) {
this.callback = callback;
}
public void startPreview() {
mCamera.startPreview();
}
public void initialize(Context mcontext) {
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int weight, int height) {
if (holder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
if (null != mCamera) {
mCamera.stopPreview();
}
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
if (null != mCamera) {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
/*
* if (null != camera) { camera.startPreview();
*/
} catch (Exception e) {
Log.d("check",
"Error starting camera preview: " + e.getMessage());
}
}
public Camera getCamera() {
return this.mCamera;
}
public void startTakePicture() {
mCamera.autoFocus(new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
takePicture();
}
});
}
public void takePicture() {
mCamera.takePicture(new ShutterCallback() {
#Override
public void onShutter() {
if (null != callback)
callback.onShutter();
}
}, new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
if (null != callback)
callback.onRawPictureTaken(data, camera);
}
}, new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
if (null != callback)
callback.onJpegPictureTaken(data, camera);
}
});
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
// mCamera.startPreview();
try {
mCamera.setPreviewDisplay(holder);
} catch (Throwable ignored) {
}
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (null != callback)
callback.onPreviewFrame(data, camera);
}
});
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
// camera.stopPreview();
mCamera.release();
mCamera = null;
}
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
Display display = getWindowManager().getDefaultDisplay();
if (display.getHeight() > display.getWidth()) {
myCamera.setDisplayOrientation(90);
show_l.setVisibility(View.GONE);
show_p.setVisibility(View.VISIBLE);
} else {
myCamera.setDisplayOrientation(0);
show_l.setVisibility(View.VISIBLE);
show_p.setVisibility(View.GONE);
}
}
private Handler checkHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (recording && count <= 15) {
if (mode == 1) {
show_l.setText(count + "/15");
} else {
show_p.setText(count + "/15");
}
}
}
};
#Override
public void onClick(View v) {
if (v.equals(objbtncapture)) {
myCameraSurfaceView.startTakePicture();
}
if (v.equals(objbtngalary)) {
// releaseCamera();
Intent i = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
final int ACTIVITY_SELECT_IMAGE = 100;
startActivityForResult(i, ACTIVITY_SELECT_IMAGE);
}
if (v.equals(objbtnflashlight)) {
if (!isfrontcamera) {
if (!flashlight) {
flashlight = true;
Parameters params = myCamera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
myCamera.setParameters(params);
} else {
flashlight = false;
Parameters params = myCamera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_OFF);
myCamera.setParameters(params);
}
}
}
if (v.equals(objbbtnfrontcam)) {
if (!cameramode) {
cameramode = true;
switchToCamera(cameramode);
} else {
cameramode = false;
switchToCamera(cameramode);
}
}
if (v.equals(objbtnback)) {
finish();
}
if (v.equals(objbtnretake)) {
objrelativeLayoutretake.setVisibility(View.GONE);
objrelativeLayout3.setVisibility(View.VISIBLE);
myCameraSurfaceView.startPreview();
}
if (v.equals(objbtnuse)) {
try {
PhotoComplete(data);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void switchToCamera(boolean frontcamera) {
releaseCamera();
if (frontcamera) {
isfrontcamera = true;
myCamera = getFrontCameraId();
} else {
isfrontcamera = false;
myCamera = getCameraInstance();
}
if (myCamera == null) {
Toast.makeText(CaptureDealImage.this, "fail to get front camera",
Toast.LENGTH_SHORT).show();
myCamera = getCameraInstance();
}
myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
mymiddlelayout = (FrameLayout) findViewById(R.id.middlelayout);
mymiddlelayout.removeAllViews();
mymiddlelayout.addView(myCameraSurfaceView);
}
Camera getFrontCameraId() {
int cameraCount = 0;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras();
Camera camera = null;
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
try {
camera = Camera.open(camIdx);
Display getOrient = getWindowManager().getDefaultDisplay();
if (getOrient.getHeight() > getOrient.getWidth()) {
camera.setDisplayOrientation(90);
}
// myCamera.unlock();
// mediaRecorder.setCamera(myCamera);
// myCamera.setParameters(myCamera.getParameters());
} catch (RuntimeException e) {
Log.e("",
"Camera failed to open: " + e.getLocalizedMessage());
}
}
}
return camera;
// No front-facing camera found
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
}
#Override
public void onShutter() {
// TODO Auto-generated method stub
}
#Override
public void onRawPictureTaken(byte[] data, Camera camera) {
// TODO Auto-generated method stub
}
#Override
public void onJpegPictureTaken(byte[] data, Camera camera) {
try {
this.data = data;
objrelativeLayoutretake.setVisibility(View.VISIBLE);
objrelativeLayout3.setVisibility(View.GONE);
} catch (Exception e) {
e.printStackTrace();
}
}
private void PhotoComplete(byte[] data) throws FileNotFoundException,
IOException {
try {
sdcardpath = String.format(getResources().getString(R.string.path),
System.currentTimeMillis());
FileOutputStream outStream = new FileOutputStream(sdcardpath);
outStream.write(data);
outStream.close();
Bundle objbundle = new Bundle();
Intent objintent = new Intent(CaptureDealImage.this,
com.flashdeal.mycamera.SetDealImageCategory.class);
objbundle.putString("from", "camera");
objbundle.putString("imagepath", sdcardpath);
Log.e("check===path", sdcardpath);
objintent.putExtras(objbundle);
startActivity(objintent);
finish();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public String onGetVideoFilename() {
// TODO Auto-generated method stub
return null;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 100 && resultCode == RESULT_OK) {
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
cursor.close();
Bundle objbundle = new Bundle();
Intent objintent = new Intent(CaptureDealImage.this,
com.flashdeal.mycamera.SetDealImageCategory.class);
objbundle.putString("from", "camera");
objbundle.putString("imagepath", filePath);
objintent.putExtras(objbundle);
startActivity(objintent);
finish();
}
}
}
But this not work and when I click front camera ,again back camera and again on capture button camera become freez.Please anyone guide me or give imp link for my requirement.
Refer this links ::
They are facing the same issue that you have.Have a look at once .
Link 1
Link 2
Hope this helps :)