import android.view.WindowManager;
import java.io.IOException;
+import java.util.regex.Pattern;
/**
* This object wraps the Camera service object and expects to be the only one talking to it. The
* @author dswitkin@google.com (Daniel Switkin)
*/
final class CameraManager {
+
private static final String TAG = "CameraManager";
+
private static final int MIN_FRAME_WIDTH = 240;
private static final int MIN_FRAME_HEIGHT = 240;
private static final int MAX_FRAME_WIDTH = 480;
private static final int MAX_FRAME_HEIGHT = 360;
+ private static final Pattern COMMA_PATTERN = Pattern.compile(",");
+
private static CameraManager cameraManager;
+
private Camera camera;
private final Context context;
private Point screenResolution;
// Camera.setPreviewCallback() on 1.5 and earlier. For Donut and later, we need to use
// the more efficient one shot callback, as the older one can swamp the system and cause it
// to run out of memory. We can't use SDK_INT because it was introduced in the Donut SDK.
- if (Integer.parseInt(Build.VERSION.SDK) <= Build.VERSION_CODES.CUPCAKE) {
- useOneShotPreviewCallback = false;
- } else {
- useOneShotPreviewCallback = true;
- }
+ useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > Build.VERSION_CODES.CUPCAKE;
}
/**
public void openDriver(SurfaceHolder holder) throws IOException {
if (camera == null) {
camera = Camera.open();
+ if (camera == null) {
+ throw new IOException();
+ }
camera.setPreviewDisplay(holder);
if (!initialized) {
}
setCameraParameters();
+ FlashlightManager.enableFlashlight();
}
}
*/
public void closeDriver() {
if (camera != null) {
+ FlashlightManager.disableFlashlight();
camera.release();
camera = null;
}
// This is the standard Android format which all devices are REQUIRED to support.
// In theory, it's the only one we should ever care about.
case PixelFormat.YCbCr_420_SP:
- return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
- rect.width(), rect.height());
// This format has never been seen in the wild, but is compatible as we only care
// about the Y channel, so allow it.
case PixelFormat.YCbCr_422_SP:
default:
// The Samsung Moment incorrectly uses this variant instead of the 'sp' version.
// Fortunately, it too has all the Y data up front, so we can read it.
- if (previewFormatString.equals("yuv420p")) {
+ if ("yuv420p".equals(previewFormatString)) {
return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height());
}
*/
private void setCameraParameters() {
Camera.Parameters parameters = camera.getParameters();
- Camera.Size size = parameters.getPreviewSize();
- Log.v(TAG, "Default preview size: " + size.width + ", " + size.height);
previewFormat = parameters.getPreviewFormat();
previewFormatString = parameters.get("preview-format");
Log.v(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
- // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
- // TODO: A better solution would be to request the supported preview resolutions
- // and pick the best match, but this parameter is not standardized in Cupcake.
- cameraResolution = new Point();
- cameraResolution.x = (screenResolution.x >> 3) << 3;
- cameraResolution.y = (screenResolution.y >> 3) << 3;
+ cameraResolution = getCameraResolution(parameters);
Log.v(TAG, "Setting preview size: " + cameraResolution.x + ", " + cameraResolution.y);
parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
return screenResolution;
}
+ private Point getCameraResolution(Camera.Parameters parameters) {
+
+ String previewSizeValueString = parameters.get("preview-size-values");
+ // saw this on Xperia
+ if (previewSizeValueString == null) {
+ previewSizeValueString = parameters.get("preview-size-value");
+ }
+
+ Point cameraResolution = null;
+
+ if (previewSizeValueString != null) {
+ Log.v(TAG, "preview-size parameter: " + previewSizeValueString);
+ cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
+ }
+
+ if (cameraResolution == null) {
+ // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
+ cameraResolution = new Point(
+ (screenResolution.x >> 3) << 3,
+ (screenResolution.y >> 3) << 3);
+ }
+
+ return cameraResolution;
+ }
+
+ private static Point findBestPreviewSizeValue(String previewSizeValueString, Point screenResolution) {
+ int bestX = 0;
+ int bestY = 0;
+ int diff = Integer.MAX_VALUE;
+ for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
+
+ previewSize = previewSize.trim();
+ int dimPosition = previewSize.indexOf('x');
+ if (dimPosition < 0) {
+ Log.w(TAG, "Bad preview-size");
+ continue;
+ }
+
+ int newX;
+ int newY;
+ try {
+ newX = Integer.parseInt(previewSize.substring(0, dimPosition));
+ newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
+ } catch (NumberFormatException nfe) {
+ Log.w(TAG, "Bad preview-size");
+ continue;
+ }
+
+ int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
+ if (newDiff == 0) {
+ bestX = newX;
+ bestY = newY;
+ break;
+ } else if (newDiff < diff) {
+ bestX = newX;
+ bestY = newY;
+ diff = newDiff;
+ }
+
+ }
+
+ if (bestX > 0 && bestY > 0) {
+ return new Point(bestX, bestY);
+ }
+ return null;
+ }
+
}