am 83c50ca7: Merge "Update ApiDemos CameraPreview activity to properly center the preview in cases where the camera hardware doesn\'t support a preview size with the same aspect ratio as the device display." into gingerbread
Merge commit '83c50ca740fabe25189601db90dc1f65ed4d2061' into gingerbread-plus-aosp * commit '83c50ca740fabe25189601db90dc1f65ed4d2061': Update ApiDemos CameraPreview activity to properly center the preview in cases where the camera hardware doesn't support a preview size with the same aspect ratio as the device display.
This commit is contained in:
@@ -21,9 +21,13 @@ import android.content.Context;
|
|||||||
import android.hardware.Camera;
|
import android.hardware.Camera;
|
||||||
import android.hardware.Camera.Size;
|
import android.hardware.Camera.Size;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.SurfaceView;
|
import android.view.SurfaceView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -32,62 +36,145 @@ import java.util.List;
|
|||||||
|
|
||||||
public class CameraPreview extends Activity {
|
public class CameraPreview extends Activity {
|
||||||
private Preview mPreview;
|
private Preview mPreview;
|
||||||
|
Camera mCamera;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// Hide the window title.
|
// Hide the window title.
|
||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
|
|
||||||
// Create our Preview view and set it as the content of our activity.
|
// Create a RelativeLayout container that will hold a SurfaceView,
|
||||||
|
// and set it as the content of our activity.
|
||||||
mPreview = new Preview(this);
|
mPreview = new Preview(this);
|
||||||
setContentView(mPreview);
|
setContentView(mPreview);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
mCamera = Camera.open();
|
||||||
|
mPreview.setCamera(mCamera);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
|
||||||
|
// Because the Camera object is a shared resource, it's very
|
||||||
|
// important to release it when the activity is paused.
|
||||||
|
if (mCamera != null) {
|
||||||
|
mPreview.setCamera(null);
|
||||||
|
mCamera.release();
|
||||||
|
mCamera = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
class Preview extends SurfaceView implements SurfaceHolder.Callback {
|
/**
|
||||||
|
* A simple wrapper around a Camera and a SurfaceView that renders a centered preview of the Camera
|
||||||
|
* to the surface. We need to center the SurfaceView because not all devices have cameras that
|
||||||
|
* support preview sizes at the same aspect ratio as the device's display.
|
||||||
|
*/
|
||||||
|
class Preview extends ViewGroup implements SurfaceHolder.Callback {
|
||||||
|
private final String TAG = "Preview";
|
||||||
|
|
||||||
|
SurfaceView mSurfaceView;
|
||||||
SurfaceHolder mHolder;
|
SurfaceHolder mHolder;
|
||||||
|
Size mPreviewSize;
|
||||||
|
List<Size> mSupportedPreviewSizes;
|
||||||
Camera mCamera;
|
Camera mCamera;
|
||||||
|
|
||||||
Preview(Context context) {
|
Preview(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
|
mSurfaceView = new SurfaceView(context);
|
||||||
|
addView(mSurfaceView);
|
||||||
|
|
||||||
// Install a SurfaceHolder.Callback so we get notified when the
|
// Install a SurfaceHolder.Callback so we get notified when the
|
||||||
// underlying surface is created and destroyed.
|
// underlying surface is created and destroyed.
|
||||||
mHolder = getHolder();
|
mHolder = mSurfaceView.getHolder();
|
||||||
mHolder.addCallback(this);
|
mHolder.addCallback(this);
|
||||||
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCamera(Camera camera) {
|
||||||
|
mCamera = camera;
|
||||||
|
if (mCamera != null) {
|
||||||
|
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
// We purposely disregard child measurements because act as a
|
||||||
|
// wrapper to a SurfaceView that centers the camera preview instead
|
||||||
|
// of stretching it.
|
||||||
|
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
|
||||||
|
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
|
||||||
|
setMeasuredDimension(width, height);
|
||||||
|
|
||||||
|
if (mSupportedPreviewSizes != null) {
|
||||||
|
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
|
if (changed && 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
// The Surface has been created, acquire the camera and tell it where
|
// The Surface has been created, acquire the camera and tell it where
|
||||||
// to draw.
|
// to draw.
|
||||||
mCamera = Camera.open();
|
|
||||||
try {
|
try {
|
||||||
mCamera.setPreviewDisplay(holder);
|
if (mCamera != null) {
|
||||||
|
mCamera.setPreviewDisplay(holder);
|
||||||
|
}
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
mCamera.release();
|
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
|
||||||
mCamera = null;
|
|
||||||
// TODO: add more exception handling logic here
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
// Surface will be destroyed when we return, so stop the preview.
|
// Surface will be destroyed when we return, so stop the preview.
|
||||||
// Because the CameraDevice object is not a shared resource, it's very
|
if (mCamera != null) {
|
||||||
// important to release it when the activity is paused.
|
mCamera.stopPreview();
|
||||||
mCamera.stopPreview();
|
}
|
||||||
mCamera.release();
|
|
||||||
mCamera = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
|
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
|
||||||
final double ASPECT_TOLERANCE = 0.05;
|
final double ASPECT_TOLERANCE = 0.1;
|
||||||
double targetRatio = (double) w / h;
|
double targetRatio = (double) w / h;
|
||||||
if (sizes == null) return null;
|
if (sizes == null) return null;
|
||||||
|
|
||||||
@@ -123,10 +210,8 @@ class Preview extends SurfaceView implements SurfaceHolder.Callback {
|
|||||||
// Now that the size is known, set up the camera parameters and begin
|
// Now that the size is known, set up the camera parameters and begin
|
||||||
// the preview.
|
// the preview.
|
||||||
Camera.Parameters parameters = mCamera.getParameters();
|
Camera.Parameters parameters = mCamera.getParameters();
|
||||||
|
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
|
||||||
List<Size> sizes = parameters.getSupportedPreviewSizes();
|
requestLayout();
|
||||||
Size optimalSize = getOptimalPreviewSize(sizes, w, h);
|
|
||||||
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
|
|
||||||
|
|
||||||
mCamera.setParameters(parameters);
|
mCamera.setParameters(parameters);
|
||||||
mCamera.startPreview();
|
mCamera.startPreview();
|
||||||
|
|||||||
Reference in New Issue
Block a user