title: Android Camera preview in a fragment
body: <p>Until now I have a full working code that plugs in a camera to see the preview of the front camera. </p>
  
  <p>What I'm trying to do now is to get that camera working inside a <code>Fragment</code>. </p>
  
  <p>Full code:</p>
  
  <p><strong>MainActivity.java</strong></p>
  
  <pre><code>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();
  }
  }
  </code></pre>
  
  <p><strong>CameraExtractionFragment.java</strong></p>
  
  <pre><code>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 &lt; 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
  }
  }
  </code></pre>
  
  <p><strong>CameraExtraction.java</strong></p>
  
  <pre><code>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&lt;Size&gt; 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() &gt; 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 &gt; 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 &lt; 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 &lt; 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&lt;Camera.Size&gt; availableSizes =  mCamera.getParameters().getSupportedPreviewSizes();
    if (availableSizes == null || availableSizes.size() &lt;= 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&lt;availableSizes.size(); a++) {
        int temp = Math.abs(size.width*size.height - availableSizes.get(a).width*availableSizes.get(a).height);
        if (temp &lt; 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;
   }
  
  }
  </code></pre>
  
  <p>But when you run the application, no image is being showed in my device. Only a white screen. Note that, as I mentioned <strong>the camera is working in an activity not containing fragments</strong>.</p>
  
  <p>So, <strong>why the main activity is shown with a white screen?</strong></p>
  
  <p>PS: <a href="https://www.dropbox.com/s/6rxqckp8b6kh6gm/ApplicationCamera.zip?dl=0">Here</a> you can download my code and test it.</p>