Until now I have a full working code that plugs in a camera to see the preview of the front camera.
What I'm trying to do now is to get that camera working inside a 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()
);
// Find the total number of cameras available
mNumberOfCameras = Camera.getNumberOfCameras();
// Find the ID of the rear-facing ("default") camera
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < mNumberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
cameraId = i;
}
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return mCameraExtraction;
}
@Override
public void onResume() {
super.onResume();
// Use mCurrentCamera to select the camera desired to safely restore
// the fragment after the camera has been changed
mCamera = Camera.open(cameraId);
mCameraExtraction.setCamera(mCamera);
}
@Override
public void onPause() {
super.onPause();
if (mCamera != null)
{
mCamera.release();
}
}
// Modo en el que se pinta la cámara: encajada por dentro o saliendo los bordes por fuera.
public enum CameraViewMode {
/**
* Inner mode
*/
Inner,
/**
* Outer mode
*/
Outer
}
}
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 run the application, no image is being showed in my device. Only a white screen. Note that, as I mentioned the camera is working in an activity not containing fragments.
So, why the main activity is shown with a white screen?
PS: Here you can download my code and test it.