Compass搭配Camera

1. CompassActivity.java

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.PowerManager;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;

public class CompassActivity extends Activity implements SensorEventListener,
        Camera.AutoFocusCallback {

    private CompassPreview compassPreview;
    private DrawView drawView;
    private SensorManager sensorManager;
    private Sensor sensorAccelerometer;
    private Sensor sensorMagneticField;
    private TextView readingPitch, readingRoll;
    private float[] valuesAccelerometer;
    private float[] valuesMagneticField;
    private float[] matrixR;
    private float[] matrixI;
    private float[] matrixValues;
    private DecimalFormat decimalFormat;
    private PowerManager powerManager;
    private PowerManager.WakeLock wakeLock;
    private ImageButton pictureBtn;
    private Camera myCamera;
    private byte[] pictureData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initWindow();
        this.setContentView(R.layout.activity_camera);
        initObject();
        initSensor();

    }

    @Override
    protected void onResume() {
        super.onResume();
        regListener();
        initDormancy();
        Load(Camera.CameraInfo.CAMERA_FACING_BACK);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregListener();
        releaseDormancy();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    public void Load(int camera_id) {
        myCamera = getCameraInstance(camera_id);
        if (myCamera != null) {
            compassPreview.initCamera(myCamera);
        }
    }

    public Camera getCameraInstance(int camera_id) {
        Camera c = null;

        try {
            c = Camera.open(camera_id);// attempt to get a Camera instance
        } catch (Exception e) {
            Log.e("CompassActivity", e.getMessage());
            Toast.makeText(this, "Camera is not release", Toast.LENGTH_SHORT)
                    .show();
        }
        return c; // returns null if camera is unavailable
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    public void onSensorChanged(SensorEvent event) {

        switch (event.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            for (int i = 0; i < 3; i++) {
                valuesAccelerometer[i] = event.values[i];
            }
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            for (int i = 0; i < 3; i++) {
                valuesMagneticField[i] = event.values[i];
            }
            break;
        }
        boolean success = SensorManager.getRotationMatrix(matrixR, matrixI,
                valuesAccelerometer, valuesMagneticField);

        if (success) {
            SensorManager.getOrientation(matrixR, matrixValues);
            double azimuth = Math.toDegrees(-matrixValues[0]);
            double pitch = Math.abs(Math.toDegrees(matrixValues[1]));
            double roll = Math.abs(Math.toDegrees(matrixValues[2]));

            drawView.updateRotate((float) azimuth, (float) pitch, (float) roll);
            readingPitch
                    .setText("Pitch : " + decimalFormat.format(pitch) + "°");
            readingRoll.setText("Roll : " + decimalFormat.format(roll) + "°");
        }
    }

    public void initWindow() {
        requestWindowFeature(Window.FEATURE_NO_TITLE); // 取消標題
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN); // 全螢幕
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    }

    public void initSensor() {

        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        sensorAccelerometer = sensorManager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        sensorMagneticField = sensorManager
                .getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        valuesAccelerometer = new float[3];
        valuesMagneticField = new float[3];
        matrixR = new float[9];
        matrixI = new float[9];
        matrixValues = new float[3];
    }

    public void regListener() {
        sensorManager.registerListener(this, sensorAccelerometer,
                SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(this, sensorMagneticField,
                SensorManager.SENSOR_DELAY_NORMAL);
        pictureBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View view) {
                myCamera.autoFocus(CompassActivity.this);
            }

        });
    }

    public void unregListener() {

        sensorManager.unregisterListener(this, sensorAccelerometer);
        sensorManager.unregisterListener(this, sensorMagneticField);
    }

    public void initObject() {
        compassPreview = (CompassPreview) this
                .findViewById(R.id.compassPreview);
        drawView = (DrawView) this.findViewById(R.id.drawView);
        readingPitch = (TextView) this.findViewById(R.id.pitchText);
        readingRoll = (TextView) this.findViewById(R.id.rollText);
        pictureBtn = (ImageButton) this.findViewById(R.id.pictureBtn);
        decimalFormat = new DecimalFormat("0.0");
        powerManager = (PowerManager) this
                .getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, this
                .getClass().getCanonicalName());
    }

    public void initDormancy() {
        wakeLock.acquire();
    }

    public void releaseDormancy() {
        wakeLock.release();
    }

    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        if (success) {
            camera.takePicture(new Camera.ShutterCallback() {

                @Override
                public void onShutter() {
                    // TODO Auto-generated method stub

                }
            }, null, jpeg);
        } else {
            Toast.makeText(CompassActivity.this, "對焦失敗", Toast.LENGTH_SHORT)
                    .show();
        }
    }

    Camera.PictureCallback jpeg = new Camera.PictureCallback() {
        /** 拍照時,onPictureTaken()會自動被呼叫 */
        public void onPictureTaken(byte[] imgData, Camera camera) {
            if (imgData != null) {
                pictureData = imgData;
                new CompassActivity.MyPictureTask().execute(Environment
                        .getExternalStorageDirectory().getPath()
                        + "/Camera_tools");
            }
        }
    };

    private class MyPictureTask extends AsyncTask<String, Integer, byte[]> {

        private ProgressDialog progresslog;
        private String showInformation;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progresslog = new ProgressDialog(CompassActivity.this, 1);
            progresslog.setMessage("Loading Picture...");
            progresslog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            progresslog.show();
        }

        @Override
        protected byte[] doInBackground(String... parameter) {

            File path = new File(parameter[0]);

            if (!path.exists()) {
                path.mkdir();
            }
            Matrix matrix = new Matrix();
            HashMap<Integer, Integer> cameraRotate = compassPreview
                    .getCameraDegree();

            matrix.postRotate(cameraRotate
                    .get(Camera.CameraInfo.CAMERA_FACING_BACK));

            try {
                String fileName = getPath(path.getPath());
                Bitmap picture = BitmapFactory.decodeByteArray(pictureData, 0,
                        pictureData.length);
                FileOutputStream fOut = new FileOutputStream(fileName);
                Bitmap bitmap = Bitmap.createBitmap(picture, 0, 0,
                        picture.getWidth(), picture.getHeight(), matrix, true);
                if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut)) {
                    showInformation = "新增圖片至" + path.getPath() + "路徑";
                }

                fOut.flush();
                fOut.close();

            } catch (Exception io) {
                Log.e("error", io.getMessage());
            }
            return null;
        }

        @Override
        protected void onPostExecute(byte[] result) {
            super.onPostExecute(result);
            progresslog.dismiss();
            progresslog = null;
            Toast.makeText(CompassActivity.this, showInformation,
                    Toast.LENGTH_SHORT).show();
        }

    }

    public String getPath(String path) {

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_kkmmss");
        String date = dateFormat.format(new Date());
        String photoFile = "Picture_" + date + ".png";
        String fileName = path + File.separator + photoFile;
        return fileName;
    }
}


2. CompassPreview.java

import java.lang.reflect.Method;
import java.util.HashMap;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.os.Build;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CompassPreview extends SurfaceView implements
        SurfaceHolder.Callback {

    private SurfaceHolder mHolder;
    private Camera myCamera;
    private Camera.CameraInfo cameraInfo;

    public CompassPreview(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    public void initCamera(Camera camera) {
        myCamera = camera;
        mHolder = this.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {

        try {
            setCameraParameter(holder, format, width, height);
        } catch (Exception e) {
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        stopCamera();
    }

    private void stopCamera() {
        myCamera.stopPreview();
        myCamera.release();
        myCamera = null;
    }

    private void setCameraParameter(SurfaceHolder holder, int format,
            int width, int height) {

        Camera.Parameters parameters = myCamera.getParameters();
        HashMap<Integer, Integer> mapCameraInfo = getCameraDegree();

        parameters.setPreviewSize(width, height);
        if (Integer.parseInt(Build.VERSION.SDK) >= 8) {
            setDisplayOrientation(myCamera,
                    mapCameraInfo.get(cameraInfo.CAMERA_FACING_BACK));

        } else {

            if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                parameters.set("orientation", "portrait");
                parameters.set("rotation",
                        mapCameraInfo.get(cameraInfo.CAMERA_FACING_BACK));
            }
            if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
                parameters.set("orientation", "landscape");
                parameters.set("rotation",
                        mapCameraInfo.get(cameraInfo.CAMERA_FACING_BACK));
            }
        }

        // List<Size> supportedPictureSizes = parameters
        // .getSupportedPictureSizes();
        //
        // for (int i = 0; i < supportedPictureSizes.size(); i++) {
        //
        // Log.e("getSupportedPictureSizes(w, h)",
        // supportedPictureSizes.get(i).width + ", "
        // + supportedPictureSizes.get(i).height + ")");
        // }
        //
        // List<Size> supportedPreviewSizes = parameters
        // .getSupportedPreviewSizes();
        // for (int i = 0; i < supportedPreviewSizes.size(); i++) {
        //
        // Log.e("getSupportedPreviewSizes(w, h)",
        // supportedPreviewSizes.get(i).width + ", "
        // + supportedPreviewSizes.get(i).height + ")");
        // }
        //
        // parameters.setPictureSize(supportedPictureSizes.get(0).width,
        // supportedPictureSizes.get(0).height);

        try {
            myCamera.setParameters(parameters);
            myCamera.setPreviewDisplay(holder);
            myCamera.startPreview();

        } catch (Exception io) {
        }

    }

    protected void setDisplayOrientation(Camera camera, int angle) {
        Method downPolymorphic;
        try {
            downPolymorphic = camera.getClass().getMethod(
                    "setDisplayOrientation", new Class[] { int.class });
            if (downPolymorphic != null)
                downPolymorphic.invoke(camera, new Object[] { angle });
        } catch (Exception io) {
        }
    }

    public HashMap<Integer, Integer> getCameraDegree() {

        HashMap<Integer, Integer> mapCameraInfo = new HashMap<Integer, Integer>();
        int numberOfCameras = Camera.getNumberOfCameras();
        cameraInfo = new Camera.CameraInfo();
        for (int camera_id = 0; camera_id < numberOfCameras; camera_id++) {
            Camera.getCameraInfo(camera_id, cameraInfo);
            mapCameraInfo.put(camera_id, cameraInfo.orientation);
        }
        return mapCameraInfo;
    }
}

 
3. DrawView.java

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceView;

public class DrawView extends SurfaceView {

    private Bitmap compassBitmap;
    private float[] apz;

    public DrawView(Context context, AttributeSet attrs) {
        super(context, attrs);
        compassBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(
                getResources(), R.drawable.compass));
        // draw method will not be called.
        setWillNotDraw(false);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int centerComW = canvas.getWidth() / 2 - (compassBitmap.getWidth() / 2);
        int centerComH = canvas.getHeight() / 2
                - (compassBitmap.getHeight() / 2);
        int centerCanW = canvas.getWidth() / 2;
        int centerCanH = canvas.getHeight() / 2;
        if (apz != null) {
            if (!(apz[1] > 20 || apz[2] > 20)) {
                canvas.rotate(apz[0], centerCanW, centerCanH);
                canvas.drawBitmap(compassBitmap, centerComW, centerComH, null);
            }
        }

    }

    public void updateRotate(float... rotate) {
        this.apz = rotate;
        this.invalidate();
    }
}

 
4. activity_camera.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.cameraactivity.CompassPreview
        android:id="@+id/compassPreview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible" >
    </com.example.cameraactivity.CompassPreview>

    <com.example.cameraactivity.DrawView
        android:id="@+id/drawView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible" >
    </com.example.cameraactivity.DrawView>

    <TextView
        android:id="@+id/rollText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_marginBottom="50dp"
        android:layout_marginLeft="27dp"
        android:textColor="@android:color/white"
        android:textSize="15sp" />

    <TextView
        android:id="@+id/pitchText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/rollText"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="22dp"
        android:textColor="@android:color/white"
        android:textSize="15sp" />

    <ImageButton
        android:id="@+id/pictureBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:background="@android:color/black"
        android:src="@android:drawable/ic_menu_camera" />

</RelativeLayout>

 
5. AndroidManifest.xml(重點程式碼)

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />


6. Compass Picture

沒有留言: