So far, I have a full working code that connects the camera to see a preview of the front camera.
Now I'm trying to get this camera to work inside Fragment .
Full code:
MainActivity.java
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_main); getFragmentManager().beginTransaction().add(R.id.mainLayout, new CameraExtractionFragment()).commit(); } }
CameraExtractionFragment.java
public class CameraExtractionFragment extends Fragment { private CameraExtraction mCameraExtraction; Camera mCamera; int mNumberOfCameras; int cameraId; int rotation; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCameraExtraction = new CameraExtraction( this.getActivity().getBaseContext(), this.getActivity().getWindowManager().getDefaultDisplay().getRotation() );
CameraExtraction.java
public class CameraExtraction extends ViewGroup implements SurfaceHolder.Callback { private final String TAG = "CameraExtraction"; Camera mCamera; SurfaceHolder mHolder; SurfaceView mSurfaceView; int mNumberOfCameras; int cameraId; Rect desiredSize; CameraViewMode cameraViewMode; boolean mSurfaceCreated = false; List<Size> mSupportedPreviewSizes; int rotation; Size mPreviewSize; public CameraExtraction(Context context, int rotation) { super(context); this.rotation = rotation; mSurfaceView = new SurfaceView(context); addView(mSurfaceView); // Install a SurfaceHolder.Callback so we get notified when the mHolder = mSurfaceView.getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); cameraViewMode = CameraViewMode.Inner; } public void setCamera(Camera camera) { mCamera = camera; if (mCamera != null) { mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes(); if (mSurfaceCreated) requestLayout(); } } public void switchCamera(Camera camera) { setCamera(camera); try { camera.setPreviewDisplay(mHolder); } catch (IOException exception) { Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); } } @SuppressLint("DrawAllocation") @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mSurfaceView == null ||mSurfaceView.getHolder() == null) return; if (mSurfaceView.getHolder().getSurface() == null) { // preview surface does not exist return; } final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); setMeasuredDimension(width, height); if (mSupportedPreviewSizes != null) { mPreviewSize = getNearestPreviewSize(mCamera.new Size(widthMeasureSpec,heightMeasureSpec)); } if (mCamera != null) { Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); mCamera.setParameters(parameters); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (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); } } } @Override public void surfaceCreated(SurfaceHolder holder) { mCamera = Camera.open(cameraId); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) { if (mSurfaceView == null || mSurfaceView.getHolder() == null) return; if (mSurfaceView.getHolder().getSurface() == null) { // preview surface does not exist return; } // set preview size and make any resize, rotate or // reformatting changes here Camera.Parameters param = mCamera.getParameters(); Point previewSize = new Point(640,480); Camera.Size size = getNearestPreviewSize(mCamera.new Size(previewSize.x,previewSize.y)); param.setPreviewSize(size.width, size.height); mCamera.setParameters(param); rotation = setCameraDisplayOrientation(cameraId, mCamera); // start preview with new settings try { mCamera.setPreviewCallback(new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { // TODO Auto-generated method stub } }); mCamera.setPreviewDisplay(mSurfaceView.getHolder()); mCamera.startPreview(); } catch (Exception e) { Log.d("AndroidControlSurfaceView", "Error starting camera preview: " + e.getMessage()); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); } } protected Rect getCameraViewSizeCompensated(Camera.Size cameraPreviewSize, Point hostViewSize) { Rect toReturn=null; float ratioWidth = hostViewSize.x / (float)cameraPreviewSize.width; float ratioHeight = hostViewSize.y / (float)cameraPreviewSize.height; switch (cameraViewMode){ case Inner: if (ratioWidth < ratioHeight) { int newHeight = (int)(cameraPreviewSize.height*ratioWidth); int y = (hostViewSize.y - newHeight) / 2; toReturn = new Rect(0, y, hostViewSize.x, y+newHeight); } else { int newWidth = (int)(cameraPreviewSize.width*ratioHeight); int x = (hostViewSize.x - newWidth) / 2; toReturn = new Rect(x, 0, x+newWidth,hostViewSize.y); } break; case Outer: if (ratioWidth < ratioHeight) { int newWidth = (int)(cameraPreviewSize.width*ratioHeight); int x = (hostViewSize.x - newWidth) / 2; toReturn = new Rect(x, 0, x+newWidth,hostViewSize.y); } else { int newHeight = (int)(cameraPreviewSize.height*ratioWidth); int y = (hostViewSize.y - newHeight) / 2; toReturn = new Rect(0, y, hostViewSize.x, y+newHeight); } break; } return toReturn; } private Camera.Size getNearestPreviewSize(Camera.Size size) { List<Camera.Size> availableSizes = mCamera.getParameters().getSupportedPreviewSizes(); if (availableSizes == null || availableSizes.size() <= 0) return null; Camera.Size toReturn = availableSizes.get(0); int distance = Math.abs(size.width*size.height - toReturn.width*toReturn.height); for (int a=1; a<availableSizes.size(); a++) { int temp = Math.abs(size.width*size.height - availableSizes.get(a).width*availableSizes.get(a).height); if (temp < distance) { distance = temp; toReturn = availableSizes.get(a); } } return toReturn; } public int setCameraDisplayOrientation(int cameraId, android.hardware.Camera camera) { CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(cameraId, info); 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); return result/90; } }
But when you launch the application, the image is not displayed on my device. Only a white screen. Please note that, as I said, the camera works in an activity that does not contain fragments .
So, why is the main activity displayed using a white screen?
PS: Here you can download my code and test it.