Skip to content
Snippets Groups Projects
CameraView.java 4.47 KiB
package org.briarproject.qrtest;

import static android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT;
import static android.hardware.Camera.Parameters.FOCUS_MODE_AUTO;
import static android.hardware.Camera.Parameters.FOCUS_MODE_MACRO;
import static android.view.SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS;

import java.io.IOException;
import java.util.List;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

@SuppressWarnings("deprecation")
public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
AutoFocusCallback {

	private static String TAG = CameraView.class.getPackage().getName();

	private Camera camera = null;
	private PreviewConsumer previewConsumer = null;
	private Size desiredSize = null;
	private int displayOrientation = 0;
	private boolean surfaceExists = false;

	public CameraView(Context context) {
		super(context);
		setKeepScreenOn(true);
	}

	void start(Camera camera, PreviewConsumer previewConsumer,
			int rotationDegrees, boolean macro) {
		this.camera = camera;
		this.previewConsumer = previewConsumer;
		setDisplayOrientation(rotationDegrees);
		Parameters params = camera.getParameters();
		List<String> modes = params.getSupportedFocusModes();
		if(macro && modes.contains(FOCUS_MODE_MACRO))
			params.setFocusMode(FOCUS_MODE_MACRO);
		else if(modes.contains(FOCUS_MODE_AUTO))
			params.setFocusMode(FOCUS_MODE_AUTO);
		camera.setParameters(params);
		SurfaceHolder holder = getHolder();
		holder.addCallback(this);
		holder.setType(SURFACE_TYPE_PUSH_BUFFERS); // Required on Android < 3.0
		if(surfaceExists) startPreview(holder);
	}

	void stop() {
		stopPreview();
		getHolder().removeCallback(this);
	}

	private void startPreview(SurfaceHolder holder) {
		try {
			camera.setPreviewDisplay(holder);
			camera.startPreview();
			camera.autoFocus(this);
			previewConsumer.start(camera);
		} catch(IOException e) {
			Log.e(TAG, "Error starting camera preview", e);
		}
	}

	private void stopPreview() {
		try {
			previewConsumer.stop();
			camera.cancelAutoFocus();
			camera.stopPreview();
		} catch(Exception e) {
			Log.e(TAG, "Error stopping camera preview", e);
		}
	}

	private void setDisplayOrientation(int rotationDegrees) {
		int orientation;
		CameraInfo info = new CameraInfo();
		Camera.getCameraInfo(0, info);
		if(info.facing == CAMERA_FACING_FRONT) {
			orientation = (info.orientation + rotationDegrees) % 360;
			orientation = (360 - orientation) % 360;
		} else {
			orientation = (info.orientation - rotationDegrees + 360) % 360;
		}
		Log.d(TAG, "Display orientation " + orientation + " degrees");
		camera.setDisplayOrientation(orientation);
		displayOrientation = orientation;
	}

	public void surfaceCreated(SurfaceHolder holder) {
		Log.d(TAG, "Surface created");
		surfaceExists = true;
		startPreview(holder);
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
		Log.d(TAG, "Surface changed");
		stopPreview();

		boolean rotatePreview = displayOrientation % 180 == 90;
		Parameters params = camera.getParameters();
		List<Size> sizes = params.getSupportedPreviewSizes();
		Size bestSize = null;
		int bestError = 0;
		for(Size size : sizes) {
			int width = rotatePreview ? size.height : size.width;
			int height = rotatePreview ? size.width : size.height;
			int widthError = Math.abs(width - w);
			int heightError = Math.abs(height - h);
			int error = Math.max(widthError, heightError);
			if(bestSize == null || error < bestError) {
				bestSize = size;
				bestError = error;
			}
		}

		Log.d(TAG, "Surface size " + w + "x" + h);
		Log.d(TAG, "Best size " + bestSize.width + "x" + bestSize.height);

		params.setPreviewSize(bestSize.width, bestSize.height);
		camera.setParameters(params);
		desiredSize = bestSize;

		startPreview(holder);
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		Log.d(TAG, "Surface destroyed");
		surfaceExists = false;
	}

	public void onAutoFocus(boolean success, Camera camera) {
		Log.d(TAG, "Auto focus: " + success);
	}

	@Override
	protected void onMeasure(int width, int height) {
		if(desiredSize == null) super.onMeasure(width, height);
		else if(displayOrientation % 180 == 90)
			setMeasuredDimension(desiredSize.height, desiredSize.width);
		else setMeasuredDimension(desiredSize.width, desiredSize.height);
	}
}