package wb.android.camera;
import android.annotation.SuppressLint;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.List;
/**
* This code is adapted from the google camera APIs. Check it online for more details
*/
@SuppressLint("ViewConstructor")
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
//logging variables
private static final String TAG = "Preview";
private static final boolean D = true;
//Constants
public static final String LANDSCAPE = "Landscape";
public static final String PORTRAIT = "Portrait";
//instance variables
final SurfaceHolder _holder;
private Size _previewSize, _pictureSize;
private CameraController _controller;
private boolean _isPortraitOreintation;
@SuppressWarnings("deprecation")
public CameraPreview(final CameraActivity cameraActivity) {
super(cameraActivity);
_holder = this.getHolder();
_holder.addCallback(this);
_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
_isPortraitOreintation = true;
_previewSize = null;
_pictureSize = null;
}
public final void changeOrientation() {
_isPortraitOreintation ^= _isPortraitOreintation;
}
public final String orientation() {
if (_isPortraitOreintation)
return PORTRAIT;
else
return LANDSCAPE;
}
final void setCameraController(final CameraController controller) {
_controller = controller;
}
/********************************************************************************************************
* Below is code from google (though partly adapted to suit my needs)
********************************************************************************************************/
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
if (D) Log.d(TAG, "onMeasure");
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (!_controller.isStarted()) return;
//Find the Optimal Preview and Camera Sizes for this device
Parameters params = _controller.getCameraParams();
if (android.os.Build.MODEL.equalsIgnoreCase("DROIDX") || android.os.Build.MODEL.equalsIgnoreCase("DROID X")) {//Droid X seems to have issues with preview sizes that are too large
_previewSize = params.getPreviewSize();
}
if (params == null) return;
List<Size> previewSizes = params.getSupportedPreviewSizes();
List<Size> pictureSizes = params.getSupportedPictureSizes();
final float ASPECT_TOLERANCE = 0.1f;
float targetRatio = (float) width / height;
if (previewSizes == null || pictureSizes == null) return;
int num;
Size size;
// ====== Determine Preview Size ======= \\
float minDiff = Float.MAX_VALUE;
num = previewSizes.size();
// Try to find an preview size match aspect ratio and size
if (_previewSize == null) {
for (int i=0; i<num; i++) {
size = previewSizes.get(i);
float ratio = (float) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - height) < minDiff) {
_previewSize = size;
minDiff = Math.abs(size.height - height);
}
}
}
// Cannot find the one match the aspect ratio for the preview size, ignore the requirement
if (_previewSize == null) {
minDiff = Float.MAX_VALUE;
for (int i=0; i<num; i++) {
size = previewSizes.get(i);
if (Math.abs(size.height - height) < minDiff) {
_previewSize = size;
minDiff = Math.abs(size.height - height);
}
}
}
// ====== Determine Picture Size ======= \\
minDiff = Float.MAX_VALUE;
num = pictureSizes.size();
targetRatio = (float) _previewSize.width / _previewSize.height;
// Try to find an preview size match aspect ratio and size - Try to find with dimensions smaller than 1024
if (_pictureSize == null) {
for (int i=0; i<num; i++) {
size = pictureSizes.get(i);
float ratio = (float) size.width / size.height;
int maxDim = (ratio > 1.0) ? size.width : size.height;
if (maxDim > 1440) continue;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - _previewSize.height) < minDiff) {
Log.e(TAG, "Thjis");
_pictureSize = size;
minDiff = Math.abs(size.height - _previewSize.height);
}
}
}
// Try to find the max picture size that matches the preview size's aspect ratio
if (_pictureSize == null) {
for (int i=0; i<num; i++) {
size = pictureSizes.get(i);
float ratio = (float) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - _previewSize.height) < minDiff) {
_pictureSize = size;
minDiff = Math.abs(size.height - _previewSize.height);
}
}
}
// Try to find the closet picture size to the preview size
if (_pictureSize == null) {
minDiff = Float.MAX_VALUE;
for (int i=0; i<num; i++) {
size = pictureSizes.get(i);
if (Math.abs(size.height - _previewSize.height) < minDiff) {
_pictureSize = size;
minDiff = Math.abs(size.height - _previewSize.height);
}
}
}
}
@Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
super.onLayout(changed, l, t, r, b);
/*
if (D) Log.d(TAG, "onLayout");
if (changed) {
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (_previewSize != null) {
if (_isPortraitOreintation) {
previewWidth = _previewSize.height;
previewHeight = _previewSize.width;
}
else {
previewWidth = _previewSize.width;
previewHeight = _previewSize.height;
}
}
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
this.layout((width - scaledChildWidth) / 2, 0, (width + scaledChildWidth) / 2, height);
}
else {
final int scaledChildHeight = previewHeight * width / previewWidth;
this.layout(l, (height - scaledChildHeight) / 2, width+l, (height + scaledChildHeight) / 2);
}
}*/
}
/*
private final Size getOptimalPreviewSize(final int w, final int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
Log.e(TAG, "oW: " + optimalSize.width + ", oH: " + optimalSize.height);
return optimalSize;
}*/
/********************************************************************************************************
* SurfaceHolder.Callback Methods
********************************************************************************************************/
// The Surface has been created, acquire the camera and tell it where to draw.
public final void surfaceCreated(final SurfaceHolder holder) {
if (D) Log.d(TAG, "surfaceCreated");
_controller.setPreviewDisplay(holder);
Parameters params = _controller.getCameraParams();
if (params != null) {
if (_previewSize != null) params.setPreviewSize(_previewSize.width, _previewSize.height);
if (_pictureSize != null) params.setPictureSize(_pictureSize.width, _pictureSize.height);
_controller.setCameraParams(params);
}
this.setWillNotDraw(false);
}
// Surface will be destroyed when we return, so stop the preview
public final void surfaceDestroyed(final SurfaceHolder holder) {
if (D) Log.d(TAG, "surfaceDestroyed");
this.setWillNotDraw(true);
_controller.stopPreview(); //Need a safe way to stop the preview when the activity isn't killed
_controller.stopCamera();
}
// Now that the size is known, set up the camera parameters and begin
public final void surfaceChanged(final SurfaceHolder holder, final int format, final int w, final int h) {
if (D) Log.d(TAG, "surfaceChanged");
_controller.startPreview();
}
}