@Override
 public void surfaceDestroyed(SurfaceHolder holder) {
   Log.d(TAG, "surfaceDestroyed");
   mCameraManager.getCamera().setPreviewCallback(null);
   mCameraManager.getCamera().stopPreview();
   mCameraManager.getCamera().release();
   mCameraManager.closeDriver();
 }
  // Called when camera take a frame
  @Override
  public void onPreviewFrame(byte[] data, Camera camera) {

    PlanarYUVLuminanceSource source =
        mCameraManager.buildLuminanceSource(data, mPreviewWidth, mPreviewHeight);

    HybridBinarizer hybBin = new HybridBinarizer(source);
    BinaryBitmap bitmap = new BinaryBitmap(hybBin);

    try {
      Result result = mQRCodeReader.decode(bitmap);

      // Notify We're found a QRCode
      if (mOnQRCodeReadListener != null) {
        // Transform resultPoints to View coordinates
        PointF[] transformedPoints = transformToViewCoordinates(result.getResultPoints());
        mOnQRCodeReadListener.onQRCodeRead(result.getText(), transformedPoints);
      }

    } catch (ChecksumException e) {
      Log.d(TAG, "ChecksumException");
      e.printStackTrace();
    } catch (NotFoundException e) {
      // Notify QR not found
      if (mOnQRCodeReadListener != null) {
        mOnQRCodeReadListener.QRCodeNotFoundOnCamImage();
      }
    } catch (FormatException e) {
      Log.d(TAG, "FormatException");
      e.printStackTrace();
    } finally {
      mQRCodeReader.reset();
    }
  }
  /**
   * **************************************************
   * SurfaceHolder.Callback,Camera.PreviewCallback
   * **************************************************
   */
  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    try {
      // Indicate camera, our View dimensions
      mCameraManager.openDriver(holder, this.getWidth(), this.getHeight());
    } catch (IOException e) {
      Log.w(TAG, "Can not openDriver: " + e.getMessage());
      mCameraManager.closeDriver();
    }

    try {
      mQRCodeReader = new QRCodeReader();
      mCameraManager.startPreview();
    } catch (Exception e) {
      Log.e(TAG, "Exception: " + e.getMessage());
      mCameraManager.closeDriver();
    }
  }
  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    Log.d(TAG, "surfaceChanged");

    if (mHolder.getSurface() == null) {
      Log.e(TAG, "Error: preview surface does not exist");
      return;
    }

    // preview_width = width;
    // preview_height = height;

    mPreviewWidth = mCameraManager.getPreviewSize().x;
    mPreviewHeight = mCameraManager.getPreviewSize().y;

    mCameraManager.stopPreview();
    mCameraManager.getCamera().setPreviewCallback(this);
    mCameraManager.getCamera().setDisplayOrientation(90); // Portrait mode

    mCameraManager.startPreview();
  }
  /**
   * Transform result to surfaceView coordinates
   *
   * <p>This method is needed because coordinates are given in landscape camera coordinates. Now is
   * working but transform operations aren't very explained
   *
   * <p>TODO re-write this method explaining each single value
   *
   * @return a new PointF array with transformed points
   */
  private PointF[] transformToViewCoordinates(ResultPoint[] resultPoints) {

    PointF[] transformedPoints = new PointF[resultPoints.length];
    int index = 0;
    if (resultPoints != null) {
      float previewX = mCameraManager.getPreviewSize().x;
      float previewY = mCameraManager.getPreviewSize().y;
      float scaleX = this.getWidth() / previewY;
      float scaleY = this.getHeight() / previewX;

      for (ResultPoint point : resultPoints) {
        PointF tmppoint = new PointF((previewY - point.getY()) * scaleX, point.getX() * scaleY);
        transformedPoints[index] = tmppoint;
        index++;
      }
    }
    return transformedPoints;
  }