1. 程式人生 > >android 自定義相機Camera2

android 自定義相機Camera2

上一篇文章我們已經運用Camera自定義了一個相機,今天我們就用Camera2自定義一個相機。Camera2是android5.0新增的api,Camera2與Camera差別比較大,採用了全新的模式,功能更加強大。今天這個例子就是Camera2拍照TextureView上面進行預覽,把之前的SurfaceView代替了。

一、開啟攝像頭

1、TextureView設定監聽

//設定TextureView監聽
tv.setSurfaceTextureListener(surfaceTextureListener);
2、在監聽中,可用狀態時開啟攝像頭
/**TextureView的監聽*/
private 
TextureView.SurfaceTextureListener surfaceTextureListener= new TextureView.SurfaceTextureListener() { //可用 @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { MainActivity.this.width=width; MainActivity.this.height=height; openCamera(); } @Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } //釋放 @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { stopCamera(); return true; } //更新 @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } };
3、開啟攝像頭(camera2採用的是CameraManager)
/**開啟攝像頭*/
private void openCamera() {
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
//設定攝像頭特性
setCameraCharacteristics(manager);
    try {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            //提示使用者開戶許可權
String[] perms = {"android.permission.CAMERA"};
ActivityCompat.requestPermissions(MainActivity.this,perms, RESULT_CODE_CAMERA);
}else {
            manager.openCamera(mCameraId, stateCallback, null);
}

    } catch (CameraAccessException e){
        e.printStackTrace();
}
}
4、設定攝像頭的一些特性
/**設定攝像頭的引數*/
private void setCameraCharacteristics(CameraManager manager)
{
    try
{
        // 獲取指定攝像頭的特性
CameraCharacteristics characteristics
                = manager.getCameraCharacteristics(mCameraId);
// 獲取攝像頭支援的配置屬性
StreamConfigurationMap map = characteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
// 獲取攝像頭支援的最大尺寸
Size largest = Collections.max(
                Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),new CompareSizesByArea());
// 建立一個ImageReader物件,用於獲取攝像頭的影象資料
imageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
ImageFormat.JPEG, 2);
//設定獲取圖片的監聽
imageReader.setOnImageAvailableListener(imageAvailableListener,null);
// 獲取最佳的預覽尺寸
previewSize = chooseOptimalSize(map.getOutputSizes(
                SurfaceTexture.class), width, height, largest);
}
    catch (CameraAccessException e)
    {
        e.printStackTrace();
}
    catch (NullPointerException e)
    {
    }
}
private static Size chooseOptimalSize(Size[] choices
        , int width, int height, Size aspectRatio)
{
    // 收集攝像頭支援的大過預覽Surface的解析度
List<Size> bigEnough = new ArrayList<>();
    int w = aspectRatio.getWidth();
    int h = aspectRatio.getHeight();
    for (Size option : choices)
    {
        if (option.getHeight() == option.getWidth() * h / w &&
                option.getWidth() >= width && option.getHeight() >= height)
        {
            bigEnough.add(option);
}
    }
    // 如果找到多個預覽尺寸,獲取其中面積最小的
if (bigEnough.size() > 0)
    {
        return Collections.min(bigEnough, new CompareSizesByArea());
}
    else
{
       //沒有合適的預覽尺寸
return choices[0];
}
}


// 為Size定義一個比較器Comparator
static class CompareSizesByArea implements Comparator<Size>
{
    @Override
public int compare(Size lhs, Size rhs)
    {
        // 強轉為long保證不會發生溢位
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                (long) rhs.getWidth() * rhs.getHeight());
}
}
二、進行拍照預覽

1、監聽攝像頭

manager.openCamera(mCameraId, stateCallback, null);
2、在攝像頭開啟是進行畫面的預覽
/**攝像頭狀態的監聽*/
private CameraDevice.StateCallback stateCallback = new CameraDevice. StateCallback()
{
    // 攝像頭被開啟時觸發該方法
@Override
public void onOpened(CameraDevice cameraDevice){
       MainActivity.this.cameraDevice = cameraDevice;
// 開始預覽
takePreview();
}

    // 攝像頭斷開連線時觸發該方法
@Override
public void onDisconnected(CameraDevice cameraDevice)
    {
        MainActivity.this.cameraDevice.close();
MainActivity.this.cameraDevice = null;
}
    // 開啟攝像頭出現錯誤時觸發該方法
@Override
public void onError(CameraDevice cameraDevice, int error)
    {
        cameraDevice.close();
}
};
3、進行預覽的設定和處理
/**
 * 開始預覽
 */
private void takePreview() {
    SurfaceTexture mSurfaceTexture = tv.getSurfaceTexture();
//設定TextureView的緩衝區大小
mSurfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
//獲取Surface顯示預覽資料
Surface mSurface = new Surface(mSurfaceTexture);
    try {
        //建立預覽請求
mCaptureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
// 設定自動對焦模式
mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
//設定Surface作為預覽資料的顯示介面
mCaptureRequestBuilder.addTarget(mSurface);
//建立相機捕獲會話,第一個引數是捕獲資料的輸出Surface列表,第二個引數是CameraCaptureSession的狀態回撥介面,當它建立好後會回撥onConfigured方法,第三個引數用來確定Callback在哪個執行緒執行,為null的話就在當前執行緒執行
cameraDevice.createCaptureSession(Arrays.asList(mSurface,imageReader.getSurface()),new CameraCaptureSession.StateCallback() {
            @Override
public void onConfigured(CameraCaptureSession session) {
                try {
                    //開始預覽
mCaptureRequest = mCaptureRequestBuilder.build();
mPreviewSession = session;
//設定反覆捕獲資料的請求,這樣預覽介面就會一直有資料顯示
mPreviewSession.setRepeatingRequest(mCaptureRequest, null, null);
} catch (CameraAccessException e) {
                    e.printStackTrace();
}

            }

            @Override
public void onConfigureFailed(CameraCaptureSession session) {

            }
        }, null);
} catch (CameraAccessException e) {
        e.printStackTrace();
}

}
三、拍照

1、進行拍照的處理和設定

/**拍照*/
private void takePicture()
{
    try
{
        if (cameraDevice == null)
        {
            return;
}
        // 建立拍照請求
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// 設定自動對焦模式
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 將imageReader的surface設為目標
captureRequestBuilder.addTarget(imageReader.getSurface());
// 獲取裝置方向
int rotation = getWindowManager().getDefaultDisplay().getRotation();
// 根據裝置方向計算設定照片的方向
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION
, ORIENTATIONS.get(rotation));
// 停止連續取景
mPreviewSession.stopRepeating();
//拍照
CaptureRequest captureRequest = captureRequestBuilder.build();
//設定拍照監聽
mPreviewSession.capture(captureRequest,captureCallback, null);
}
    catch (CameraAccessException e)
    {
        e.printStackTrace();
}
2、監聽拍照結果(成功後恢復預覽)
/**監聽拍照結果*/
private CameraCaptureSession.CaptureCallback captureCallback= new CameraCaptureSession.CaptureCallback()
{
    // 拍照成功
@Override
public void onCaptureCompleted(CameraCaptureSession session,CaptureRequest request,TotalCaptureResult result)
    {
        // 重設自動對焦模式
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
// 設定自動曝光模式
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
        try {
            //重新進行預覽
mPreviewSession.setRepeatingRequest(mCaptureRequest, null, null);
} catch (CameraAccessException e) {
            e.printStackTrace();
}

    }

    @Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
        super.onCaptureFailed(session, request, failure);
}
};
四、拍照的圖片儲存到本地相簿(用的是ImageReader進行接收圖片)
/**監聽拍照的圖片*/
private ImageReader.OnImageAvailableListener imageAvailableListener= new ImageReader.OnImageAvailableListener()
{
    // 當照片資料可用時激發該方法
@Override
public void onImageAvailable(ImageReader reader) {

        //先驗證手機是否有sdcard
String status = Environment.getExternalStorageState();
        if (!status.equals(Environment.MEDIA_MOUNTED)) {
            Toast.makeText(getApplicationContext(), "你的sd卡不可用。", Toast.LENGTH_SHORT).show();
            return;
}
        // 獲取捕獲的照片資料
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] data = new byte[buffer.remaining()];
buffer.get(data);
//手機拍照都是存到這個路徑
String filePath = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";
String picturePath = System.currentTimeMillis() + ".jpg";
File file = new File(filePath, picturePath);
        try {
            //存到本地相簿
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(data);
fileOutputStream.close();
//顯示圖片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
iv.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
            e.printStackTrace();
} catch (IOException e) {
            e.printStackTrace();
} finally {
            image.close();
}
    }


};
五、完整的程式碼

1、activity程式碼

package com.sunshanglei.camera.oneselfcamera;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
 * use 自定義相機Camera2
 * author 孫尚磊
 * create time 2017-4-25
 */
public class MainActivity extends AppCompatActivity{
    private TextureView tv;
    private Button btn;
    private String mCameraId = "0";//攝像頭id(通常0代表後置攝像頭,1代表前置攝像頭)
private final int RESULT_CODE_CAMERA=1;//判斷是否有拍照許可權的標識碼
private CameraDevice cameraDevice;
    private CameraCaptureSession mPreviewSession;
    private CaptureRequest.Builder mCaptureRequestBuilder,captureRequestBuilder;
    private CaptureRequest mCaptureRequest;
    private ImageReader imageReader;
    private int height=0,width=0;
    private Size previewSize;
    private ImageView iv;
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
    static
{
        ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}

    @Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextureView) findViewById(R.id.tv);
btn = (Button) findViewById(R.id.btn);
iv= (ImageView) findViewById(R.id.iv);
//拍照
btn.setOnClickListener(new View.OnClickListener() {
            @Override
public void onClick(View v) {
                takePicture();
}
        });
//設定TextureView監聽
tv.setSurfaceTextureListener(surfaceTextureListener);
}

    @Override
protected void onPause() {
        super.onPause();
        if(cameraDevice!=null) {
            stopCamera();
}
    }

    @Override
protected void onResume() {
        super.onResume();
startCamera();
}

    /**TextureView的監聽*/
private TextureView.SurfaceTextureListener surfaceTextureListener= new TextureView.SurfaceTextureListener() {

        //可用
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            MainActivity.this.width=width;
MainActivity.this.height=height;
openCamera();
}


        @Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

        }

        //釋放
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            stopCamera();
            return true;
}

        //更新
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {

        }
    };
/**開啟攝像頭*/
private void openCamera() {
        CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
//設定攝像頭特性
setCameraCharacteristics(manager);
        try {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                //提示使用者開戶許可權
String[] perms = {"android.permission.CAMERA"};
ActivityCompat.requestPermissions(MainActivity.this,perms, RESULT_CODE_CAMERA);
}else {
                manager.openCamera(mCameraId, stateCallback, null);
}

        } catch (CameraAccessException e){
            e.printStackTrace();
}
    }


    /**設定攝像頭的引數*/
private void setCameraCharacteristics(CameraManager manager)
    {
        try
{
            // 獲取指定攝像頭的特性
CameraCharacteristics characteristics
                    = manager.getCameraCharacteristics(mCameraId);
// 獲取攝像頭支援的配置屬性
StreamConfigurationMap map = characteristics.get(
                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
// 獲取攝像頭支援的最大尺寸
Size largest = Collections.max(
                    Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),new CompareSizesByArea());
// 建立一個ImageReader物件,用於獲取攝像頭的影象資料
imageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
ImageFormat.JPEG, 2);
//設定獲取圖片的監聽
imageReader.setOnImageAvailableListener(imageAvailableListener,null);
// 獲取最佳的預覽尺寸
previewSize = chooseOptimalSize(map.getOutputSizes(
                    SurfaceTexture.class), width, height, largest);
}
        catch (CameraAccessException e)
        {
            e.printStackTrace();
}
        catch (NullPointerException e)
        {
        }
    }
    private static Size chooseOptimalSize(Size[] choices
            , int width, int height, Size aspectRatio)
    {
        // 收集攝像頭支援的大過預覽Surface的解析度
List<Size> bigEnough = new ArrayList<>();
        int w = aspectRatio.getWidth();
        int h = aspectRatio.getHeight();
        for (Size option : choices)
        {
            if (option.getHeight() == option.getWidth() * h / w &&
                    option.getWidth() >= width && option.getHeight() >= height)
            {
                bigEnough.add(option);
}
        }
        // 如果找到多個預覽尺寸,獲取其中面積最小的
if (bigEnough.size() > 0)
        {
            return Collections.min(bigEnough, new CompareSizesByArea());
}
        else
{
           //沒有合適的預覽尺寸
return choices[0];
}
    }


    // 為Size定義一個比較器Comparator
static class CompareSizesByArea implements Comparator<Size>
    {
        @Override
public int compare(Size lhs, Size rhs)
        {
            // 強轉為long保證不會發生溢位
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                    (long) rhs.getWidth() * rhs.getHeight());
}
    }



    /**攝像頭狀態的監聽*/
private CameraDevice.StateCallback stateCallback = new CameraDevice. StateCallback()
    {
        // 攝像頭被開啟時觸發該方法
@Override
public void onOpened(CameraDevice cameraDevice){
           MainActivity.this.cameraDevice = cameraDevice;
// 開始預覽
takePreview();
}

        // 攝像頭斷開連線時觸發該方法
@Override
public void onDisconnected(CameraDevice cameraDevice)
        {
            MainActivity.this.cameraDevice.close();
MainActivity.this.cameraDevice = null;
}
        // 開啟攝像頭出現錯誤時觸發該方法
@Override
public void onError(CameraDevice cameraDevice, int error)
        {
            cameraDevice.close();
}
    };
/**
     * 開始預覽
     */
private void takePreview() {
        SurfaceTexture mSurfaceTexture = tv.getSurfaceTexture();
//設定TextureView的緩衝區大小
mSurfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
//獲取Surface顯示預覽資料
Surface mSurface = new Surface(mSurfaceTexture);
        try {
            //建立預覽請求
mCaptureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
// 設定自動對焦模式
mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
//設定Surface作為預覽資料的顯示介面
mCaptureRequestBuilder.addTarget(mSurface);
//建立相機捕獲會話,第一個引數是捕獲資料的輸出Surface列表,第二個引數是CameraCaptureSession的狀態回撥介面,當它建立好後會回撥onConfigured方法,第三個引數用來確定Callback在哪個執行緒執行,為null的話就在當前執行緒執行
cameraDevice.createCaptureSession(Arrays.asList(mSurface,imageReader.getSurface()),new CameraCaptureSession.StateCallback() {
                @Override
public void onConfigured(CameraCaptureSession session) {
                    try {
                        //開始預覽
mCaptureRequest = mCaptureRequestBuilder.build();
mPreviewSession = session;
//設定反覆捕獲資料的請求,這樣預覽介面就會一直有資料顯示
mPreviewSession.setRepeatingRequest(mCaptureRequest, null, null);
} catch (CameraAccessException e) {
                        e.printStackTrace();
}

                }

                @Override
public void onConfigureFailed(CameraCaptureSession session) {

                }
            }, null);
} catch (CameraAccessException e) {
            e.printStackTrace();
}

    }


    /**拍照*/
private void takePicture()
    {
        try
{
            if (cameraDevice == null)
            {
                return;
}
            // 建立拍照請求
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// 設定自動對焦模式
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 將imageReader的surface設為目標
captureRequestBuilder.addTarget(imageReader.getSurface());
// 獲取裝置方向
int rotation = getWindowManager().getDefaultDisplay().getRotation();
// 根據裝置方向計算設定照片的方向
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION
, ORIENTATIONS.get(rotation));
// 停止連續取景
mPreviewSession.stopRepeating();
//拍照
CaptureRequest captureRequest = captureRequestBuilder.build();
//設定拍照監聽
mPreviewSession.capture(captureRequest,captureCallback, null);
}
        catch (CameraAccessException e)
        {
            e.printStackTrace();
}
    }

    /**監聽拍照結果*/
private CameraCaptureSession.CaptureCallback captureCallback= new CameraCaptureSession.CaptureCallback()
    {
        // 拍照成功
@Override
public void onCaptureCompleted(CameraCaptureSession session,CaptureRequest request,TotalCaptureResult result)
        {
            // 重設自動對焦模式
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
// 設定自動曝光模式
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            try {
                //重新進行預覽
mPreviewSession.setRepeatingRequest(mCaptureRequest, null, null);
} catch (CameraAccessException e) {
                e.printStackTrace();
}

        }

        @Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
            super.onCaptureFailed(session, request, failure);
}
    };
/**監聽拍照的圖片*/
private ImageReader.OnImageAvailableListener imageAvailableListener= new ImageReader.OnImageAvailableListener()
    {
        // 當照片資料可用時激發該方法
@Override
public void onImageAvailable(ImageReader reader) {

            //先驗證手機是否有sdcard
String status = Environment.getExternalStorageState();
            if (!status.equals(Environment.MEDIA_MOUNTED)) {
                Toast.makeText(getApplicationContext(), "你的sd卡不可用。", Toast.LENGTH_SHORT).show();
                return;
}
            // 獲取捕獲的照片資料
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            byte[] data = new byte[buffer.remaining()];
buffer.get(data);
//手機拍照都是存到這個路徑
String filePath = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";
String picturePath = System.currentTimeMillis() + ".jpg";
File file = new File(filePath, picturePath);
            try {
                //存到本地相簿
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(data);
fileOutputStream.close();
//顯示圖片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
iv.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
                e.printStackTrace();
} catch (IOException e) {
                e.printStackTrace();
} finally {
                image.close();
}
        }


    };
@Override
public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults){
        switch(permsRequestCode){
            case RESULT_CODE_CAMERA:
                boolean cameraAccepted = grantResults[0]==PackageManager.PERMISSION_GRANTED;
                if(cameraAccepted){
                    //授權成功之後,呼叫系統相機進行拍照操作等
openCamera();
}else{
                    //使用者授權拒絕之後,友情提示一下就可以了
Toast.makeText(MainActivity.this,"請開啟應用拍照許可權",Toast.LENGTH_SHORT).show();
}
                break;
}
    }

    /**啟動拍照*/
private void startCamera(){
        if (tv.isAvailable()) {
            if(cameraDevice==null) {
                openCamera();
}
        } else {
            tv.setSurfaceTextureListener(surfaceTextureListener);
}
    }

    /**
     * 停止拍照釋放資源*/
private void stopCamera(){
        if(cameraDevice!=null){
            cameraDevice.close();
cameraDevice=null;
}

    }
}

2、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">
    <TextureView
android:id="@+id/tv"
android:layout_above="@+id/ll_bottom"
android:layout_width=<