カメラテスト用サンプル

package com.example.camera;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

    // カメラ
    private Camera myCamera;

    // カメラ用サーフェイスビュー
    private SurfaceView mySurfaceView;

    // 地磁気・加速度センサー 
    private SensorManager mySensor;
    
    // 地磁気・加速度センサー情報
    private static final int MATRIX_SIZE = 16;
    private static final int DIMENSION = 3;
    private float[] magneticValues = new float[DIMENSION];
    private float[] accelerometerValues = new float[DIMENSION];
    private float[] orientationValues = new float[DIMENSION];
    
    /**
     * カメラのイベント処理
     */
    private PictureCallback mPictureListener = 

        new PictureCallback() {

            @Override
            public void onPictureTaken(byte[] data, Camera camera) {

                // データを生成する
                Bitmap tmp_bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                int width = tmp_bitmap.getWidth();
                int height = tmp_bitmap.getHeight();

                // 画像データを回転する
                int rad_y = radianToDegree(orientationValues[2]);
                Matrix matrix = new Matrix();
                if ((rad_y > -45 && rad_y <= 0) || (rad_y > 0 && rad_y <= 45)) {
                    matrix.setRotate(90);
                } else if (rad_y > 45 && rad_y <= 135) {
                    matrix.setRotate(180);
                } else if ((rad_y > 135 && rad_y <= 180) || (rad_y >= -180 && rad_y <= -135)) {
                    matrix.setRotate(-90);
                } else if (rad_y > -135 && rad_y <= -45) {
                    matrix.setRotate(0);
                }
                Bitmap bitmap = Bitmap.createBitmap(tmp_bitmap, 0, 0, width, height, matrix, true);

                // ギャラリーに保存
                String name = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", java.util.Locale.JAPAN).format(new Date()) + ".jpg";
                MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, name, null);
                
                Toast.makeText(MainActivity.this, "保存しました。", Toast.LENGTH_SHORT).show();
                
                // カメラを再開
                myCamera.startPreview();
            }
        };
    
    /**
     * カメラ用サーフェイスのイベント処理
     */
    private SurfaceHolder.Callback mSurfaceListener = 

        new SurfaceHolder.Callback() {
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                myCamera.stopPreview();
                myCamera.release();
                myCamera = null;
            }
            
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                myCamera = Camera.open();
                try {
                    myCamera.setPreviewDisplay(holder);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                myCamera.stopPreview();
                
                Camera.Parameters parameters = myCamera.getParameters();
            
                // 画面の向きを設定
                boolean portrait = isPortrait();
                if (portrait) {
                    myCamera.setDisplayOrientation(90);
                } else {
                    myCamera.setDisplayOrientation(0);
                }
                
                // 対応するプレビューサイズ・保存サイズを取得する
                List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes();
                List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
                
                // 最大解像度を選択
                Size pictureSize = getOptimalPictureSize(pictureSizes);
                // 写真サイズに近くて最も大きいプレビューサイズを選択する
                Size previewSize = getOptimalPreviewSize(previewSizes, pictureSize.width, pictureSize.height);

                parameters.setPreviewSize(previewSize.width, previewSize.height);
                parameters.setPictureSize(pictureSize.width, pictureSize.height);
                
                // サーフェイスのサイズをカメラのプレビューサイズと同じ比率に設定
                android.view.ViewGroup.LayoutParams layoutParams = mySurfaceView.getLayoutParams();
                double preview_raito = (double)previewSize.width / (double)previewSize.height;
                if (width > height) {
                    // 横長
                    int new_height = (int)(width / preview_raito);
                    if (new_height <= height) {
                        layoutParams.height = height;
                    } else {
                        int new_width = (int)(height * preview_raito); 
                        layoutParams.width = new_width;
                    }
                } else {
                    // 縦長
                    int new_width = (int)(height / preview_raito);
                    if (new_width <= width) {
                        layoutParams.width = new_width;
                    } else {
                        int new_height = (int)(width * preview_raito); 
                        layoutParams.height = new_height;
                    }
                }
                mySurfaceView.setLayoutParams(layoutParams);

                // パラメータを設定してカメラを再開
                myCamera.setParameters(parameters);
                myCamera.startPreview();
            }
        };
            
    /**
     * オートフォーカスのイベント処理
     */
    private AutoFocusCallback mAutoFocusListener = 
        new AutoFocusCallback() {           
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
            }
        };
    
    /**
     * センサー制御のイベント処理
     */
    private SensorEventListener mSensorEventListener =

        new SensorEventListener() {
            
            @Override
            public void onSensorChanged(SensorEvent event) {
                
                // Nexus7では常にSENSOR_STATUS_UNRELIABLEになるのでチェックしない
                /*
                if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
                    return;
                */
                
                switch (event.sensor.getType()) {
                    case Sensor.TYPE_MAGNETIC_FIELD:
                        // 地磁気センサ
                        magneticValues = event.values.clone();
                        break;
                    case Sensor.TYPE_ACCELEROMETER:
                        // 加速度センサ(Nexus7ではサポート外?)
                        accelerometerValues = event.values.clone();
                        break;
                }
                
                if (magneticValues != null && accelerometerValues != null) {
                    float[] rotationMatrix = new float[MATRIX_SIZE];
                    float[] inclinationMatrix = new float[MATRIX_SIZE];
                    float[] remapedMatrix = new float[MATRIX_SIZE];
                    
                    // 加速度センサと地磁気センタから回転行列を取得
                    SensorManager.getRotationMatrix(rotationMatrix, inclinationMatrix, accelerometerValues, magneticValues);
                    
                    SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, remapedMatrix);
                    SensorManager.getOrientation(remapedMatrix, orientationValues);
                }
            }
            
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
            }
        };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // カメラプレビューの設定
        mySurfaceView = (SurfaceView)findViewById(R.id.surface_view);
        SurfaceHolder holder = mySurfaceView.getHolder();
        holder.addCallback(mSurfaceListener);
        
        // センサーを取得する
        mySensor = (SensorManager)getSystemService(SENSOR_SERVICE);

        Button buttonOK = (Button)this.findViewById(R.id.buttonSave);
        buttonOK.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                buttonSave_onClick();
            }
        });
    
    }

    @Override
    public void onResume() {

        super.onResume();
        
        // 地磁気センサ
        mySensor.registerListener(mSensorEventListener,
                                    mySensor.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                                    SensorManager.SENSOR_DELAY_UI);
        
        // 加速度センサ
        mySensor.registerListener(mSensorEventListener,
                                    mySensor.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                                    SensorManager.SENSOR_DELAY_UI);
    }
    
    @Override
    public void onPause() {
        super.onPause();
        mySensor.unregisterListener(mSensorEventListener);
    }
    
    /**
     * 画面の向きを取得する(縦ならtrue)
     */
    private boolean isPortrait() {
        return (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
    }
    
    /**
     * 大きすぎない写真サイズを選択する(300万画素以下、4:3のもの)
     */
    private Size getOptimalPictureSize(List<Size> sizes) {

        double targetRatio = (double)4 / 3;
        
        for (Size size : sizes) {
            double ratio = (double) size.width / size.height;
            int gasosu = size.width * size.height;
            if (gasosu < (300 * 10000) && Math.abs(ratio - targetRatio) < 0.1) {
                return size;
            }
        }
        
        return sizes.get(0);
    }
    
    /**
     * 写真サイズに近くて最も大きいプレビューサイズを選択する
     */
    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {

        if (sizes == null) {
            return null;
        }

        double targetRatio = (double) w / h;
        
        for (Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) < 0.1) {
                return size;
            }
        }

        return sizes.get(0);
    }

    /**
     * ラジアンで計測した角度を、相当する度に変換する
     */
    private int radianToDegree(float rad) {
        return (int)Math.floor(Math.toDegrees(rad));
    }
    
    /**
     * 画面タッチ時でオートフォーカス
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Camera.Parameters params = myCamera.getParameters();
            if (!params.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_FIXED)) {
                myCamera.autoFocus(mAutoFocusListener);
            }
        }
        return true;
    }
    
    /**
     * 写真保存
     */
    protected void buttonSave_onClick() {
        myCamera.takePicture(null, null, mPictureListener);
    }

}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.camera"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.camera.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <SurfaceView
        android:id="@+id/surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/buttonSave"
        android:layout_alignParentTop="true" />

	<Button
	    android:id="@+id/buttonSave"
	    android:layout_width="120dip"
	    android:layout_height="50dip"
	    android:layout_alignParentBottom="true"
	    android:text="Save" >

    </Button> 

</RelativeLayout>