Hello there I am working on an android custom camera app and facing a problem of the camera preview stretching on the following device on their front camera:
huawei Honor 4c (only on front facing camera)
HTC One M7 (only on front facing camera)
Some other devices also...as I have just the following devices to test so may be problem resides on other devices too.
The thing is that the camera preview works very well with the back camera but it only stretches when I use my app with the front facing camera!
The Code
Here is the code I am using for my Camera Preview Class:
import android.content.Context;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
//Variables de' Preview
private SurfaceHolder mHolder;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
private int FOCUS_AREA_SIZE=300;
public static Camera previewCamera;
////////////////////////
//protected LOGGER keys
protected final String EXCEPTION_KEY="xception";
//////////////////////////
public CameraPreview(Context context, Camera camera) {
super(context);
//get the camera
previewCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = previewCamera.getParameters().getSupportedPreviewSizes();
// 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);
mHolder.setKeepScreenOn(true);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try{
//when the surface is created, we can set the camera to draw images in this surfaceholder
previewCamera.setPreviewDisplay(surfaceHolder);
previewCamera.startPreview();
} catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceCreated: "+exp.toString());
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
//before changing the application orientation, you need to stop the preview, rotate and then start it again
if(mHolder.getSurface() == null)//check if the surface is ready to receive camera data
return;
try{
previewCamera.stopPreview();
} catch (Exception e){
//this will happen when you are trying the camera if it's not running
}
//now, recreate the camera preview
try{
//set the camera preview on every preview change
setPreview();
previewCamera.setPreviewDisplay(mHolder);
previewCamera.startPreview();
} catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceChanged: "+exp.toString());
}
}
public void setPreview(){
try{
//set the focusable true
this.setFocusable(true);
//set the touch able true
this.setFocusableInTouchMode(true);
//set the camera display orientation lock
previewCamera.setDisplayOrientation(90);
//get the camera parameters
Camera.Parameters parameters = previewCamera.getParameters();
//set the preview size
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
//set the parameter
previewCamera.setParameters(parameters);
}catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM setPreview: "+exp.toString());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//our app has only one screen, so we'll destroy the camera in the surface
//if you are using with more screens, please move this code your activity
try{
//handle in Activity onResume and onPause
}catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceDestroyed: "+exp.toString());
}
}
//Override Methods here
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try{
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = PreviewSizeParameters.getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM onMeasure: "+exp.toString());
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void stopPreviewAndFreeCamera() {
if (previewCamera != null) {
// Call stopPreview() to stop updating the preview surface.
previewCamera.stopPreview();
// Important: Call release() to release the camera for use by other
// applications. Applications should release the camera immediately
// during onPause() and re-open() it during onResume()).
previewCamera.release();
previewCamera = null;
}
}
//end of class here
}
Can somebody please tell me what am I missing in my code because it only affects on some devices using FRONT FACING CAMERA only.
Thanks
The following code worked in my environment.
Call getOptimalPreviewSize in surfaceChanged with SurfaceView's with and height.
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
...
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int w, int h) {
//before changing the application orientation, you need to stop the preview, rotate and then start it again
if(mHolder.getSurface() == null)//check if the surface is ready to receive camera data
return;
try{
previewCamera.stopPreview();
} catch (Exception e){
//this will happen when you are trying the camera if it's not running
}
//now, recreate the camera preview
try{
//set the focusable true
this.setFocusable(true);
//set the touch able true
this.setFocusableInTouchMode(true);
//set the camera display orientation lock
previewCamera.setDisplayOrientation(90);
Camera.Parameters params = previewCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size optimalSize = getOptimalPreviewSize(sizes,w,h);
params.setPreviewSize(optimalSize.width,optimalSize.height);
previewCamera.setParameters(params);
previewCamera.setPreviewDisplay(mHolder);
previewCamera.startPreview();
} catch(Exception exp){
Log.i(EXCEPTION_KEY,"FROM surfaceChanged: "+exp.toString());
}
}
...
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
//end of class here
}
Related
I am getting a very interesting behavior by Android Studio in my project. The calls to different activities are not executing sequentially!
I am building a project where in the calls are like this:
button.setOnClickListener()
{
(1) call to cusom camera acivity
(2) call to activity showing preview of latest captured image
(3) call to a doCrop() function
}
But when executed, the actual flow is:
(1) call to the doCrop() function
(2) call to activity showing preview of image captured
(3) call to cusom camera acivity
The custom camera activity handles all the necessary SurfaceHolder and SurfaceView operations.
Is this effect happening as the SurfaceView layout creation and destroying takes more time and android switches to easier one task first?
Even so, it should skip to preview activity and not to doCrop() call.
What is happening here? Please give some pointers !
Thank you!
EDIT:
The naming is:
MainActivity - main activity
Preview - creates camera instance
CameraPreview - Handles SurfaceView etc
ImagePreview -Shows specified image
Main activity code:
photo.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
File temp = new File(//path to store image);
imageUri=Uri.fromFile(temp);
Intent intent = new Intent(MainActivity.this,Preview.class);
startActivity(intent);
// Image Preview Activity
Intent intent1=new Intent(MainActivity.this,ImagePreview.class);
startActivity(intent1);
//Crop function
doCrop();
}
});
The preview activity code:
public class Preview extends Activity {
private static final String TAG = "CamTestActivity";
CameraPreview preview;
Button buttonClick;
Camera camera;
Activity act;
Context ctx;
Uri uri;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ctx = this;
act = this;
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_preview);
preview = new CameraPreview(this, (SurfaceView)findViewById(R.id.surfaceView));
preview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
((FrameLayout) findViewById(R.id.layout)).addView(preview);
preview.setKeepScreenOn(true);
buttonClick = (Button) findViewById(R.id.btnCapture);
buttonClick.setOnClickListener(new OnClickListener()
{
public void onClick(View v) {
camera.takePicture(shutterCallback, rawCallback, pngCallback);
}
});
}
#Override
protected void onResume() {
super.onResume();
int numCams = Camera.getNumberOfCameras();
if(numCams > 0){
try{
camera = Camera.open(0);
camera.startPreview();
preview.setCamera(camera);
} catch (RuntimeException ex){
Toast.makeText(ctx, getString(R.string.camera_not_found), Toast.LENGTH_LONG).show();
}
}
}
#Override
protected void onPause() {
if(camera != null) {
camera.stopPreview();
preview.setCamera(null);
camera.release();
camera = null;
}
super.onPause();
}
private void resetCam() {
camera.startPreview();
preview.setCamera(camera);
}
private void refreshGallery(File file) {
Intent mediaScanIntent = new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(file));
sendBroadcast(mediaScanIntent);
}
ShutterCallback shutterCallback = new ShutterCallback() {
public void onShutter() {
}
};
PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
}
};
PictureCallback pngCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
new SaveImageTask().execute(data);
resetCam();
Log.d(TAG, "onPictureTaken - png");
}
};
private class SaveImageTask extends AsyncTask<byte[], Void, Void> {
#Override
protected Void doInBackground(byte[]... data) {
// save the image
}
catch (Exception e) { e.printStackTrace();}
return null;
}
}
}
CameraPreview code:
class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
CameraPreview(Context context, SurfaceView sv) {
super(context);
mSurfaceView = sv;
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if(mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}
}
I think this is more of a design issue.
Should you really be opening more than one activity at once?
When an activity is started, it's put on top of the history stack, which could give the illusion that it's happening the other way round.
But I can't comment any further until I see code.
UPDATE: Yep, design issue.
This is the way it should work:
Onclick action in MainActivity should ONLY open Preview activity using startActivityForResult().
User takes photo, triggering setResult() and closing the camera activity.
Result gets returned to MainActivity, triggering onActivityResult()
Code in onActivityResult starts ImagePreview activity.
onCreate function in ImagePreview triggers doCrop();
I do suggest you have a good read of the Android Documentation here:
http://developer.android.com/guide/components/activities.html
Android is less flexible (or more helpful) than other platforms and it's essential that you have a good understanding of the API.
Activity startup code is asynchronous, and if you launch several activities simultaneously, like this:
startActivity(intent1);
startActivity(intent2);
startActivity(intent3);
it is not guaranteed, that they'll be shown to user sequentially, that is, in "launch order".
This is expected behaviour, and you normally should not do such a thing, as it is indication of your application design flaw
So what you are trying to do is launch 3 activities simultaneously.These all need to be handled in onActivityResult(). But a user cannot access 3 activities simultaneously.
so modifying your flow.
it should be something like
start CameraActivity
In the onActivityResult() of your calling activity ,you call do crop and do what you want.
You need to revisit your workflow because:
you are not launching 3 activites.
you are triggerring events based on user interaction and hence the sequence of functions should not be controlled from your code.
Your tasks are executing in wrong order because they are called asynchronously. To execute them in the order you have specified make a synchronous call, which can be done using startActivityForResult(intent, requestCode);
I have a custom camera application and I want for any preview sizes to display it in full screen mode without stretching the camera preview image.
For this, I need to make the surfaceView larger than the screen in order to keep aspect ratio, so actually the user will see less than camera actually captures.
For some reason, I cannot make the SurfaceView larger than the screen size.
What I've tried so far:
resize camera preview in surfaceChanged method
resize camera preview in on onMeasure method
resize it in in onLayout method
adding FLAG_LAYOUT_NO_LIMITS to activity - info
adding android:clipChildren for the surface view - info
setting width in xml: android:layout_width="852px"
getWindow().setLayout(852, 1280); in activity
but without any success - the behaviour is the same each time: it appears ok for 1 second and after that it gets stretched.
Here is the code:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final int CAMERA_ROTATE_ANGLE = 90;
private SurfaceHolder cameraHolder;
private Camera androidHardCamera;
private Context context;
public CameraPreview(Context context) {
super(context);
this.context = context;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
cameraHolder = getHolder();
cameraHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
cameraHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
this.androidHardCamera = camera;
if (androidHardCamera != null) {
requestLayout();
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
if (androidHardCamera != null) {
androidHardCamera.stopPreview();//this is needed for devices with API level < 14 (from doc.: Starting
// from API level 14, this method, aka setDisplayOrientation, can be called when preview is active.)
androidHardCamera.setDisplayOrientation(CAMERA_ROTATE_ANGLE);//force the preview Display Orientation
// to Portrait (rotate camera orientation/display to portrait)
//holder.setFixedSize(852, 1280);
androidHardCamera.setPreviewDisplay(holder);
androidHardCamera.startPreview();
}
} catch (IOException e) {
}
}
#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 (cameraHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
androidHardCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this.getLayoutParams();
layoutParams.height = 1280;
layoutParams.width = 852;
this.setLayoutParams(layoutParams);
//cameraHolder.setFixedSize(852, 1280);
requestLayout();
// start preview with new settings
try {
androidHardCamera.setPreviewDisplay(cameraHolder);
androidHardCamera.startPreview();
} catch (Exception e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
// #Override
// protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// // super.onMeasure(widthMeasureSpec, heightMeasureSpec); //To change body of overridden methods use File | Settings | File Templates.
// //super.onMeasure(852, 1280);
// setMeasuredDimension(852, 1280);
// }
}
public class MyActivity extends Activity{
private Camera camera;
private CameraPreview previewCamera;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
setContentView(R.layout.camera_screen);
previewCamera = new CameraPreview(this);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(previewCamera);
//getWindow().setLayout(852, 1280);
}
#Override
protected void onResume() {
// Create an instance of Camera
camera = getCameraInstance(1);
if (camera == null) {
Toast.makeText(this, "Camera in use!", Toast.LENGTH_LONG).show();
} else {
previewCamera.setCamera(camera);
camera.stopPreview();
Camera.Parameters p = camera.getParameters();
p.setPreviewSize(176, 144);
// p.setPreviewSize(480, 800);
camera.setParameters(p);
startPreviewCamera();
}
super.onResume();
}
#Override
protected void onPause() {
releaseCameraAndPreview();
super.onPause();
}
public Camera getCameraInstance(int cameraInstance) {
Camera c = null;
try {
c = Camera.open(cameraInstance);
} catch (Exception e) {
// Camera is not available (in use or does not exist)
System.out.println("exception: " + e);
}
return c;
}
public void startPreviewCamera() {
//Force the preview Display Orientation to Portrait (rotate camera orientation/display to portrait)
camera.setDisplayOrientation(90);
camera.startPreview();
}
public void releaseCameraAndPreview() {
if (camera != null) {
camera.stopPreview(); // updating the preview surface
camera.setPreviewCallback(null);
// camera.lock(); //if we don't lock the camera, release() will fail on some devices
camera.release();
camera = null;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- This is the container for the camera preview screen -->
<FrameLayout android:id="#+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:layout_weight="1"/>
</LinearLayout>
Here is the entire project: https://www.dropbox.com/sh/96jih9kw5zmmnzy/z7VX16T30M
I am testing on a S3 device. On a S2 device seems to wok fine... I just do not know what to do more to solve this issue...
UPDATE 1
For example Sony Xperia has a screen display of 480 / 854.
One of the preview sizes I can use is 176 / 144.
In order to display full screen size I need to have the preview camera size of 698 / 854 - but I do not know how to set this value and where.
The code below is not working... the camera preview is stretched/elongated.
import android.app.Activity;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
public class CameraPreview extends Activity implements Preview.PreviewListener {
private Preview mPreview;
private Camera mCamera;
FrameLayout preview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
// Create our Preview view and set it as the content of our activity.
mPreview = new Preview(this);
preview = (FrameLayout) findViewById(R.id.surface_camera);
preview.addView(mPreview);
Display display = getWindowManager().getDefaultDisplay();
getDisplaySize(display);
}
private static Point getDisplaySize(final Display display) {
final Point point = new Point();
try {
display.getSize(point);
} catch (java.lang.NoSuchMethodError ignore) {
point.x = display.getWidth();
point.y = display.getHeight();
}
System.out.println("============: Screen " + point.x + "/" + point.y);
return point;
}
#Override
protected void onResume() {
super.onResume();
mCamera = Camera.open(1);
mPreview.setCamera(mCamera, this);
}
#Override
protected void onPause() {
super.onPause();
if (mCamera != null) {
mPreview.setCamera(null, null);
mCamera.release();
mCamera = null;
}
}
#Override
public void onSurfaceChanged() {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) preview.getLayoutParams();
params.setMargins(0, -218, 0, 0);
preview.setLayoutParams(new FrameLayout.LayoutParams(480, 854));
preview.setLayoutParams(params);
preview.setVisibility(View.VISIBLE);
}
}
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
import java.util.List;
class Preview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private PreviewListener listener;
public static interface PreviewListener {
void onSurfaceChanged();
}
Preview(Context context) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera, PreviewListener listener) {
this.listener = listener;
mCamera = camera;
if (mCamera != null) {
List<Camera.Size> mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for (Camera.Size s : mSupportedPreviewSizes) {
System.out.println("============: " + s.width + "/" + s.height);
}
requestLayout();
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e("Error: ", "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
mCamera.stopPreview(); // pe Xpedia daca nu pui asta crapa la setDisplayOrientation
// Now that the size is known, set up the camera parameters and beginthe preview.
Camera.Parameters parameters = mCamera.getParameters();
mCamera.setDisplayOrientation(90);
parameters.setPreviewSize(176, 144);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
// #Override
// protected void onSizeChanged(\int w, int h, int oldw, int oldh) {
// super.onSizeChanged(w, h, oldw, oldh);
// //setLayoutParams(new LayoutParams((int)RATIO * w, w));
//
// FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
// setLayoutParams(new FrameLayout.LayoutParams(960, 1280));
// params.setMargins(0, -120, 0,0);
// setLayoutParams(params);
//
// //preview.setVisibility(View.VISIBLE);
// }
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); //To change body of overridden methods use File | Settings | File Templates.
// FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
// setLayoutParams(new FrameLayout.LayoutParams(698, 854));
// params.setMargins(0, -218, 0,0);
// setLayoutParams(params);
}
//https://stackoverflow.com/questions/11853297/change-size-of-android-custom-surfaceview
#Override
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed) {
//setLayoutParams();
listener.onSurfaceChanged();
//(this).layout(0, 0, viewWidth , viewHeight);
}
}
}
This is a class test which calculates the correct surface view size based on display screen size and camera preview size:
public class Test {
/**
* Determine proper width to be used for surface view in order to not stretch the camera live preview.
*/
public static void main(String[] args) {
// camera preview size:
int surfaceViewWidth = 176;
int surfaceViewHeight = 144;
int holder;
if (surfaceViewWidth > surfaceViewHeight) {
holder = surfaceViewWidth;
surfaceViewWidth = surfaceViewHeight;
surfaceViewHeight = holder;
}
//device screen display sizes:
int width = 480;
int height = 854;
double sc1 = (double) width / surfaceViewWidth;
double sc2 = (double) height / surfaceViewHeight;
double rez;
if (sc1 > sc2) {
rez = sc1;
} else {
rez = sc2;
}
System.out.println("Width/height: " + (int) (surfaceViewWidth * rez) + "/" + (int) (surfaceViewHeight * rez)); // size of the preview size we need to set
System.out.println(((int) (surfaceViewWidth * rez))-width); // difference between preview size and device screen size = whit how much is bigger the preview size than screen size
}
}
First, remove source of crashes: startPreviewCamera called in onResume.
Camera preview shall be started in SurfaceHolder.Callback methods.
Then you should know that you can set preview size only to sizes reported by Camera.Parameters.getSupportedPreviewSizes. And these sizes will most likely be smaller or equal to device's screen size.
Then you simply call
Camera.Parameters p = camera.getParameters();
p.setPreviewSize(w, h); // one of supported sizes
camera.setParameters(p);
Then Surface of preview will have that size (possibly rotated and w/h swapped). And this surface will be rescaled by Android to size of your CameraPreview view when being drawn, so it's also important how you set size of your CameraPreview.
You can set fixed size of your CameraPreview simply by calling
previewCamera.setLayoutParams(new FrameLayout.LayoutParams(w, h));
So in short, you set requested preview size in Camera.setParameters, and you size your preview view as desired, possibly to same size as preview, as is your requirement. Your preview view then may be equal to screen size or be smaller (assuming camera doesn't provide preview bigger than screen). If camera provides bigger preview than screen, you can still call preview.setX, preview.setY to move it around.
Now i am developing Camera app for i need front and back cameras simultaneously.My requirement is when i open my app first it will show back surface view and also i have one button when i press one button it will switch to front camera surface view and also when i press button second time it will again switch to back camera for that i write this code.
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import java.io.IOException;
import java.util.List;
import com.example.R;
public class MainActivity extends Activity {
private Preview mPreview;
Camera mCamera;
int numberOfCameras;
int cameraCurrentlyLocked;
// The first rear facing camera
int defaultCameraId;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Hide the window title.
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Create a RelativeLayout container that will hold a SurfaceView,
// and set it as the content of our activity.
mPreview = new Preview(this);
setContentView(mPreview);
// Find the total number of cameras available
numberOfCameras = Camera.getNumberOfCameras();
// Find the ID of the default camera
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++)
{
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
{
defaultCameraId = i;
}
}
}
#Override
protected void onResume() {
super.onResume();
// Open the default i.e. the first rear facing camera.
mCamera = Camera.open();
cameraCurrentlyLocked = defaultCameraId;
mPreview.setCamera(mCamera);
}
#Override
protected void onPause() {
super.onPause();
// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null) {
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate our menu which can gather user input for switching camera
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.camera_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.switch_cam:
// check for availability of multiple cameras
if (numberOfCameras == 1) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("camera_alert")
.setNeutralButton("Close", null);
AlertDialog alert = builder.create();
alert.show();
return true;
}
// OK, we have multiple cameras.
// Release this camera -> cameraCurrentlyLocked
if (mCamera != null) {
mCamera.stopPreview();
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
// Acquire the next camera and request Preview to reconfigure
// parameters.
mCamera = Camera
.open((cameraCurrentlyLocked + 1) % numberOfCameras);
cameraCurrentlyLocked = (cameraCurrentlyLocked + 1)
% numberOfCameras;
mPreview.switchCamera(mCamera);
// Start the preview
mCamera.startPreview();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
Preview(Context context) {
super(context);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}
public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}
}
and my menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/switch_cam"
android:title="#string/switch_cam" />
</menu>
when i write this code i get error
menu cannot be resolved or is not a field and
switch_cam cannot be resolved or is not a field
pleae help me
if(valueofcam.equalsIgnoreCase("front")){
// Find the ID of the default camera
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
defaultCameraId = i;
// Toast.makeText(getApplicationContext(), "front", Toast.LENGTH_LONG).show();
}
else if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
defaultCameraId = i;
// Toast.makeText(getApplicationContext(), ""+defaultCameraId, Toast.LENGTH_LONG).show();
}
}
}
camera = Camera.open(defaultCameraId);
Use cameraview from Google, and tune this Object in activity_main.xml:
<com.google.android.cameraview.CameraView
android:id="#+id/camera"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:autoFocus="true"
app:aspectRatio="4:3"
app:facing="front"
app:flash="off"
android:background="#android:color/black" />
URL: https://github.com/google/cameraview
I've found many questions here about android camera preview orientation problems. All the fixes involve fixing the screen orientation to landscape or calling camera.setDisplayOrientation(90) or calling params.setRotation(90). I can't find the combination of settings which actually make it work when held in landscape orientation.
The activity is fixed to landscape mode with android:screenOrientation="landscape".
My problem is that if I hold the camera in portrait orientation and start up the application it works fine (by which I mean that it properly shows the image as a landscape). If I hold the camera in landscape orientation when starting the application the picture is all messed up (sort of interlaced). If I use camera.setDisplayOrientation(90); the picture is no longer messed up, but the image is oriented sideways.
Strangely, if I remove the android:screenOrientation="landscape" and allow the screen to rotate, I still have the same problems, but if I rotate the phone to portrait it looks fine in portrait. If I rotate it back to landscape then it looks fine in landscape! My only problem is that it won't work correctly when it first starts up.
import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.util.Log;
import android.view.*;
public class CameraView extends SurfaceView
{
//Callback for the surfaceholder
SurfaceHolder.Callback surfaceHolderListener = new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
try {
camera=Camera.open();
} catch(Exception e) {
Log.e("CameraView","Couldn't open the camera.",e);
}
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable e) {
Log.e("CameraView","Couldn't call setPreviewDisplay.",e);
}
}
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
if(camera!=null) {
Parameters params = camera.getParameters();
List<Size> sizes = params.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, w, h);
params.setPreviewSize(optimalSize.width, optimalSize.height);
camera.setParameters(params);
camera.startPreview();
}
}
public void surfaceDestroyed(SurfaceHolder arg0) {
if(camera!=null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
}
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
};
public CameraView(Context ctx) {
super(ctx);
previewHolder = this.getHolder();
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
previewHolder.addCallback(surfaceHolderListener);
setBackgroundColor(Color.TRANSPARENT);
}
public CameraView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
}
private Camera camera;
private SurfaceHolder previewHolder;
}
EDIT:
The real problem seems to be that something happens after surfaceChanged which screws things up. I found that if I start the camera preview and then add a debug point at the end of surfaceChanged the camera looks fine. Then if I step forward about 20 steps it suddenly looks screwed up.
I solved this (in a way which I think is a complete hack) by using the orientation change listener to update the orientation exactly one time and then disable itself. I just needed something which would activate after the view was initially set up. I could probably have done it elsewhere.
If anyone has any idea how to fix this without having it be this completely stupid, please help!
/** This works fine for me, but it's a hack. */
import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.OrientationEventListener;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CameraView3
extends SurfaceView
{
private static Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
private class CameraSurfaceHolder
extends OrientationEventListener
implements SurfaceHolder.Callback
{
CameraSurfaceHolder(Context ctx) {
super(ctx);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
camera= Camera.open();
} catch(Exception e) {
Log.e("CameraView","Couldn't open the camera.",e);
}
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable e) {
Log.e("CameraView","Couldn't call setPreviewDisplay.",e);
}
}
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
}
public void surfaceDestroyed(SurfaceHolder arg0) {
if(camera!=null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
}
}
#Override
public void onOrientationChanged(int orientation) {
if(camera!=null) {
DisplayMetrics dm = ctx.getResources().getDisplayMetrics();
camera.stopPreview();
CameraView3.this.layout(0, 0, dm.widthPixels-1, dm.heightPixels-1);
camera.startPreview();
disable();
return;
}
}
}
public CameraView3(Context ctx) {
super(ctx);
this.ctx = ctx;
previewHolder = this.getHolder();
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceHolderListener = new CameraSurfaceHolder(ctx);
previewHolder.addCallback(surfaceHolderListener);
surfaceHolderListener.enable();
setBackgroundColor(Color.TRANSPARENT);
}
private Context ctx;
private Camera camera;
private SurfaceHolder previewHolder;
private CameraSurfaceHolder surfaceHolderListener;
private Size optimalSize;
}
In summary, the first version I posted worked fine on my Nexus One. But, it doesn't work on my Skyrocket. I need to use the second version to make it work there.
Strangely, if I remove the android:screenOrientation="landscape" and
allow the screen to rotate, I still have the same problems, but if I
rotate the phone to portrait it looks fine in portrait.
First of all note that camera preview orientation has nothing to do with Activity orientation. Both are different. When you are changing device orientation, you have to call camera.setDisplayOrientation to set the orientation of the preview according to direction.
This orientation you have to set in degrees. This you can get from setting the OrientationEventListener in your camera perview. In onOrientationChanged(int orientation), you will get the exact rotation angle of device in degrees.
Don't forget to calculate rotation as API onOrientationChanged(int orientation) will be called for even a small degree angular change in device orientation. You can see this question as a reference.
I developed an android2.3 project ,copy the sample code "CameraPreview" from ApiDemos,and run it on my evo 4g mobile,the back camera was correct ,when switch to front facing camera ,the screen was "green screen",what's the problem?
CameraPreview
// ----------------------------------------------------------------------
import java.io.IOException;
import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
public class CameraPreview extends Activity
{
private Preview mPreview;
Camera mCamera;
int numberOfCameras;
int cameraCurrentlyLocked;
// The first rear facing camera
int defaultCameraId;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Hide the window title.
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Create a RelativeLayout container that will hold a SurfaceView,
// and set it as the content of our activity.
mPreview = new Preview(this);
setContentView(mPreview);
// Find the total number of cameras available
numberOfCameras = Camera.getNumberOfCameras();
// Find the ID of the default camera
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++)
{
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
{
defaultCameraId = i;
}
}
}
#Override
protected void onResume()
{
super.onResume();
// Open the default i.e. the first rear facing camera.
mCamera = Camera.open();
cameraCurrentlyLocked = defaultCameraId;
mPreview.setCamera(mCamera);
}
#Override
protected void onPause()
{
super.onPause();
// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null)
{
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate our menu which can gather user input for switching camera
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.camera_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
// Handle item selection
switch (item.getItemId())
{
case R.id.switch_cam:
// check for availability of multiple cameras
if (numberOfCameras == 1)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(this.getString(R.string.camera_alert)).setNeutralButton("Close", null);
AlertDialog alert = builder.create();
alert.show();
return true;
}
// OK, we have multiple cameras.
// Release this camera -> cameraCurrentlyLocked
if (mCamera != null)
{
mCamera.stopPreview();
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
// Acquire the next camera and request Preview to reconfigure
// parameters.
mCamera = Camera.open((cameraCurrentlyLocked + 1)
% numberOfCameras);
cameraCurrentlyLocked = (cameraCurrentlyLocked + 1)
% numberOfCameras;
mPreview.switchCamera(mCamera);
// Start the preview
mCamera.startPreview();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
// ----------------------------------------------------------------------
/**
* A simple wrapper around a Camera and a SurfaceView that renders a centered
* preview of the Camera to the surface. We need to center the SurfaceView
* because not all devices have cameras that support preview sizes at the same
* aspect ratio as the device's display.
*/
class Preview extends ViewGroup implements SurfaceHolder.Callback
{
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
Preview(Context context)
{
super(context);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera)
{
mCamera = camera;
if (mCamera != null)
{
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}
public void switchCamera(Camera camera)
{
setCamera(camera);
try
{
camera.setPreviewDisplay(mHolder);
}
catch (IOException exception)
{
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null)
{
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
if (changed && getChildCount() > 0)
{
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null)
{
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth)
{
final int scaledChildWidth = previewWidth * height
/ previewHeight;
child.layout((width - scaledChildWidth) / 2, 0, (width + scaledChildWidth) / 2, height);
} else
{
final int scaledChildHeight = previewHeight * width
/ previewWidth;
child.layout(0, (height - scaledChildHeight) / 2, width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder)
{
// The Surface has been created, acquire the camera and tell it where
// to draw.
try
{
if (mCamera != null)
{
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception)
{
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder)
{
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null)
{
mCamera.stopPreview();
}
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h)
{
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes)
{
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff)
{
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null)
{
minDiff = Double.MAX_VALUE;
for (Size size : sizes)
{
if (Math.abs(size.height - targetHeight) < minDiff)
{
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
{
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kiterive.magicmirror"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="9" />
<!-- We will request access to the camera, saying we require a camera
of some sort but not one with autofocus capability. -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".MagicMirrorActivity"
android:label="#string/app_name"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The EVO 4G (as of this writing) runs Android 2.2, which lacks support for the 2.3 front-facing camera APIs. I'm rather surprised your code example runs without tripping an exception for the 2.3 API calls you are invoking.
Most likely it is a device issue, drivers or something else.
Try testing it on another device.
Also make sure the device is running Android 2.3 or higher, below that it isn't supported.