Listing 15-23: Surface View skeleton implementation
Hi,
I am trying to implement a Surface View to draw information on a camera preview. I am using this listing as a guide. I am confused though as I can't work out when the resume() method is called. A call to this is needed to initialise the thread, but I can't work out where to call it without it crashing my application. Without this call, mySurfaceViewThread is always null.
Can anyone please help, or direct me to a good augmented reality example?
This is my code.
package com.example.augmentedreality;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.RectF;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
public class CustomCameraView extends SurfaceView implements SurfaceHolder.Callback {
private Camera camera;
private SurfaceHolder previewHolder;
protected float bearing;
private MySurfaceViewThread mySurfaceViewThread;
private boolean hasSurface;
private Paint textPaint;
float[] aValues = new float[3];
float[] mValues = new float[3];
Context context;
public static SensorManager sensorManager;
public CustomCameraView(Context context) {
super(context);
this.context = context;
// Create a new SurfaceHolder and assign this class as its callback.
previewHolder = getHolder();
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_P USH_BUFFERS);
previewHolder.addCallback(this);
hasSurface = false;
toast("added callback");
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(Color.MAGENTA);
textPaint.setFakeBoldText(true);
textPaint.setSubpixelText(true);
textPaint.setTextAlign(Align.LEFT);
textPaint.setTextSize(40);
sensorManager = (SensorManager)context.getSystemService(Context.SE NSOR_SERVICE);
Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELER OMETER);
Sensor magField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETI C_FIELD);
sensorManager.registerListener(sensorEventListener , accelerometer, SensorManager.SENSOR_DELAY_FASTEST);
sensorManager.registerListener(sensorEventListener , magField, SensorManager.SENSOR_DELAY_FASTEST);
}
public void resume() {
// Create and start the graphics update thread.
toast("resume");
if (mySurfaceViewThread == null) {
mySurfaceViewThread = new MySurfaceViewThread();
}
if (hasSurface == true) {
mySurfaceViewThread.start();
toast("thread started");
}
}
public void pause() {
toast("pause");
// Kill the graphics update thread
if (mySurfaceViewThread != null) {
mySurfaceViewThread.requestExitAndWait();
mySurfaceViewThread = null;
}
}
public void surfaceCreated(SurfaceHolder holder) {
toast("surface created");
hasSurface = true;
camera=Camera.open();
if (mySurfaceViewThread != null) {
mySurfaceViewThread.start();
toast("thread started");
}
try
{
camera.setPreviewDisplay(previewHolder);
camera.startPreview();
hasSurface = true;
}
catch (Throwable e) {
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
toast("surface destroyed");
hasSurface = false;
pause();
camera.stopPreview();
camera.release();
camera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
toast("surface changed");
Parameters params = camera.getParameters();
params.setPreviewSize(width, height);
params.setPictureFormat(PixelFormat.JPEG);
params.setPreviewFormat(PixelFormat.JPEG);
camera.setParameters(params);
camera.startPreview();
if (mySurfaceViewThread != null) mySurfaceViewThread.onWindowResize(width, height);
}
class MySurfaceViewThread extends Thread {
private boolean done;
MySurfaceViewThread() {
super();
toast("thread initialised");
done = false;
}
@Override
public void run() {
toast("thread.run");
SurfaceHolder surfaceHolder = previewHolder;
int height = getMeasuredHeight();
int width = getMeasuredWidth();
int px = width / 2;
int py = height / 2;
Point center = new Point(px, py);
int radius = Math.min(px, py) - 2;
RectF boundingBox = new RectF( center.x - radius,
center.y - radius,
center.x + radius,
center.y + radius);
// Repeat the drawing loop until the thread is stopped
while (!done)
{
toast("in run loop");
Canvas canvas = surfaceHolder.lockCanvas();
// TODO: Draw on the canvas
textPaint.setStrokeWidth(1);
//String text = "Bearing = " + bearing;
String text = "text";
canvas.drawText(text, px, py, textPaint);
textPaint.setStrokeWidth(2);
canvas.drawOval(boundingBox, textPaint);
canvas.restore();
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
public void requestExitAndWait() {
// Mark this thread as complete and combine into
// the main application thread.
done = true;
try {
join();
} catch (InterruptedException ex) { }
}
public void onWindowResize(int w, int h) {
// Deal with a change in the available surface size.
}
}
private float[] calculateOrientation() {
float[] values = new float[3];
float[] R = new float[9];
float[] outR = new float[9];
SensorManager.getRotationMatrix(R, null, aValues, mValues);
SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, outR);
SensorManager.getOrientation(outR, values);
// Convert from Radians to Degrees
values[0] = (float) Math.toDegrees(values[0]);
values[1] = (float) Math.toDegrees(values[1]);
values[2] = (float) Math.toDegrees(values[2]);
return values;
}
private void updateOrientation(float[] values) {
bearing = values[0];
//Toast.makeText(getContext(), "Bearing = " + bearing, Toast.LENGTH_SHORT).show();
}
SensorEventListener sensorEventListener = new SensorEventListener(){
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
{
aValues = event.values;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
{
mValues = event.values;
}
updateOrientation(calculateOrientation());
}
};
private void toast(String str){
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, str, duration);
toast.show();
}
}
|