Android原生使用camera2实现预览拍照Demo

214 阅读8分钟

1.预览画面的尺寸更新后,要动态根据更新TextureView的尺寸和比例

// 获取屏幕宽度和高度
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
displayWidth = displayMetrics.widthPixels;
displayHeight = displayMetrics.heightPixels;

2. 根据屏幕更新textureView,设置3:4的画面预览框(BufferSize的比例要和textureView一致,否则旋转相机时画面是比例会拉伸)

textureView.getSurfaceTexture().setDefaultBufferSize(displayWidth/3*4,displayWidth);
ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(textureView.getWidth(), textureView.getWidth()*4/3);
textureView.setLayoutParams(layoutParams);

3. 对应的取景框也要根据这个比例去更新取景框的位置要在画面的中间

        // 获取屏幕宽度和高度
        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        displayWidth = displayMetrics.widthPixels;
        displayHeight = displayMetrics.heightPixels;
        //设置预览框宽高
        ConstraintLayout.LayoutParams layoutParams1 = new ConstraintLayout.LayoutParams(displayWidth, displayWidth*4/3);
        frameLayout.setLayoutParams(layoutParams1);



        RoundedRectBorderView roundedRectBorderView = new RoundedRectBorderView(this);
        roundedRectBorderView.setBackgroundColor(Color.TRANSPARENT);
        FrameLayout.LayoutParams layoutParams2 = new FrameLayout.LayoutParams((int) (displayWidth * 0.7), (int) (displayWidth * 0.7 / 36 * 46));
        layoutParams2.gravity = Gravity.CENTER;
        roundedRectBorderView.setLayoutParams(layoutParams2);
        // 将TextView添加到LinearLayout容器中
        frameLayout.addView(roundedRectBorderView);

完整代码如下:

这是矩形取景框的代码

package com.xxxxxxx.digital.aicamera.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class RoundedRectBorderView extends View {
    private static final String TAG = "RoundedRectBorderView";
    private Paint paint;
    private RectF rectBorder ,rectV,rectH;
    private final float borderWidth = 16;
    private final int radius = 40;

    public RoundedRectBorderView(Context context) {
        super(context);
        init();
    }

    public RoundedRectBorderView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RoundedRectBorderView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {

        paint = new Paint();
        setLayerType(View.LAYER_TYPE_SOFTWARE, paint); //PorterDuffXfermode 需要关闭硬件加速
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(borderWidth); // Adjust the border width as needed
        paint.setColor(0xFF0000FF); // Blue color, you can change it as needed
        rectBorder = new RectF(); // Define the rounded rectangle coordinates
        rectH = new RectF();
        rectV = new RectF();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.d(TAG,"qwd onMeasure widthMeasureSpec:" + widthMeasureSpec + ";heightMeasureSpec:" + heightMeasureSpec);

        Log.d(TAG,"qwd onMeasure getWidth:" + getWidth() + ";getHeight:" + getHeight());
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        Log.d(TAG,"qwd onLayout left:" + left + ";top:" + top);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int width = getWidth();
        int height = getHeight();
        float left = borderWidth/2;//因为矩形边框是以中心线往两侧扩展宽度
        float top = borderWidth/2;
        rectBorder.set(left, top, width-left, height-top);
        canvas.drawRoundRect(rectBorder, radius, radius, paint); // 圆角矩形框

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); //以下类似于橡皮模式
        rectV.set(left + 120, top, width-left - 120, height-top); // 设置矩形的初始位置和大小
        canvas.drawRect(rectV,paint);

        rectH.set(left, top+140, width-left, height-top-140); // 设置矩形的初始位置和大小
        canvas.drawRect(rectH,paint);
        paint.setXfermode(null); // 清除Xfermode
    }
}

这是Activity代码

package com.xxxxx.digital.aicamera;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
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.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Environment;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
import android.view.Gravity;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.xxxxx.digital.aicamera.http.StringCallBack;
import com.xxxxx.digital.aicamera.http.XRetrofit;
import com.xxxxx.digital.aicamera.view.FramingView;
import com.xxxxx.digital.aicamera.view.RoundedRectBorderView;
import com.orhanobut.logger.Logger;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    TextureView textureView;
    TextureView.SurfaceTextureListener surfaceTextureListener;
    CameraManager cameraManager;
    CameraDevice.StateCallback cam_stateCallback;
    CameraDevice opened_camera;
    Surface texture_surface;
    CameraCaptureSession.StateCallback cam_capture_session_stateCallback;
    CameraCaptureSession.CaptureCallback still_capture_callback;
    CameraCaptureSession cameraCaptureSession;
    CaptureRequest.Builder requestBuilder;
    CaptureRequest.Builder requestBuilder_image_reader;
    ImageReader imageReader;
    Surface imageReaderSurface;
    Bitmap bitmap;
    CaptureRequest request;
    CaptureRequest takephoto_request;
    Button takephoto_btn;
    ImageView takephoto_imageView;
    FrameLayout root_frame_layout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "onCreate");
        setContentView(R.layout.activity_main);
        textureView=findViewById(R.id.texture_view_camera2);
        takephoto_btn=findViewById(R.id.btn_camera2_takephoto);
        takephoto_imageView= findViewById(R.id.image_view_preview_image);
        root_frame_layout = findViewById(R.id.root_frame_layout);
        initRectFrame(root_frame_layout);

        surfaceTextureListener=new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                Log.d(TAG, "onSurfaceTextureAvailable surface:"+surface);
                texture_surface=new Surface(textureView.getSurfaceTexture());
                openCamera();
            }
            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
                Log.d(TAG, "onSurfaceTextureSizeChanged surface:"+surface);
            }
            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                Log.d(TAG, "onSurfaceTextureDestroyed surface:"+surface);
                return false;
            }
            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {

            }
        };
        textureView.setSurfaceTextureListener(surfaceTextureListener);

        //B4. 相机点击事件
        takephoto_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //B4.1 配置request的参数 拍照模式(这行代码要调用已启动的相机 opened_camera,所以不能放在外面
                try {
                    requestBuilder_image_reader = opened_camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
                requestBuilder_image_reader.set(CaptureRequest.JPEG_ORIENTATION,0);//根据资料Camera2不需要自己调整角度
                requestBuilder_image_reader.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
                //B4.2 配置request的参数 的目标对象
                requestBuilder_image_reader.addTarget(imageReaderSurface );
                try {
                    //B4.3 触发拍照
                    cameraCaptureSession.capture(requestBuilder_image_reader.build(),null,null);
                    //暂停预览,并实现画面卡住
                    cameraCaptureSession.stopRepeating();
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
        });

        myOrientationEventListener = new MyOrientationEventListener(this);

        initSensor(this);
    }

    int displayWidth;
    int displayHeight;
    private void initRectFrame(FrameLayout frameLayout){

        // 获取屏幕宽度和高度
        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        displayWidth = displayMetrics.widthPixels;
        displayHeight = displayMetrics.heightPixels;
        //设置预览框宽高
        ConstraintLayout.LayoutParams layoutParams1 = new ConstraintLayout.LayoutParams(displayWidth, displayWidth*4/3);
        frameLayout.setLayoutParams(layoutParams1);


//        // 创建一个TextView
//        FramingView framingView = new FramingView(this);
//        framingView.setBackgroundColor(Color.TRANSPARENT);
//        Log.i(TAG, "initRectFrame width=" + width + "height=" + height);
//
//        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams((int) (width * 0.7), (int) (width * 0.7 / 36 * 46));
//        layoutParams.gravity = Gravity.CENTER;
//        framingView.setLayoutParams(layoutParams);
//        // 将TextView添加到LinearLayout容器中
//        frameLayout.addView(framingView);

        RoundedRectBorderView roundedRectBorderView = new RoundedRectBorderView(this);
        roundedRectBorderView.setBackgroundColor(Color.TRANSPARENT);
        FrameLayout.LayoutParams layoutParams2 = new FrameLayout.LayoutParams((int) (displayWidth * 0.7), (int) (displayWidth * 0.7 / 36 * 46));
        layoutParams2.gravity = Gravity.CENTER;
        roundedRectBorderView.setLayoutParams(layoutParams2);
        // 将TextView添加到LinearLayout容器中
        frameLayout.addView(roundedRectBorderView);


    }

    int mDeviceOrientation = 0;
    private MyOrientationEventListener myOrientationEventListener;
    public class MyOrientationEventListener extends OrientationEventListener {

        public MyOrientationEventListener(Context context) {
            super(context);
        }

        @Override
        public void onOrientationChanged(int orientation) {
            // We keep the last known orientation. So if the user first orient
            // the camera then point the camera to floor or sky, we still have
            // the correct orientation.
            if (orientation != ORIENTATION_UNKNOWN) {
                mDeviceOrientation = normalize(orientation);
            }
        }

        private int normalize(int orientation) {
            if ((orientation > 315) || (orientation <= 45)) {
                return 0;
            }

            if (orientation > 45 && orientation <= 135) {
                return 90;
            }

            if (orientation <= 225) {
                return 180;
            }

            if (orientation > 225 && orientation <= 315) {
                return 270;
            }

            return  0;
        }
    }

    private Size getAppropriatePreviewSize(Size[] outputSizes) {
        // 遍历所有支持的预览尺寸
        for (Size size : outputSizes) {
            // 选择宽高比接近16:9的尺寸
            if (size.getWidth() * 9 == size.getHeight() * 16) {
                return size;
            }
        }
        // 如果没有找到,则返回第一个支持的尺寸
        return outputSizes[0];
    }

    private Size getPreviewSize(CameraDevice cameraDevice) throws CameraAccessException {
        StreamConfigurationMap streamConfigurationMap = cameraManager.getCameraCharacteristics(opened_camera.getId()).get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        Size[] previewSizes = streamConfigurationMap.getOutputSizes(SurfaceHolder.class);
        Size previewSize = Collections.min(Arrays.asList(previewSizes), new Comparator<Size>() {
            @Override
            public int compare(Size lhs, Size rhs) {
                // 按照面积排序
                return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
            }
        });

        // 选择4:3比例的预览尺寸
        for (Size size : previewSizes) {
            if (size.getWidth() == size.getHeight() * 4 / 3) {
                previewSize = size;
                break;
            }
        }

        return previewSize;
    }


    private void openCamera() {
        cameraManager= (CameraManager) getSystemService(Context.CAMERA_SERVICE);  // 初始化
        cam_stateCallback=new CameraDevice.StateCallback() {
            @Override
            public void onOpened(@NonNull CameraDevice camera) {
                opened_camera=camera;
                try {
                    // 获取最合适的4:3比例尺寸
                    //Size previewSize = getPreviewSize(opened_camera);
                    // 选择合适的预览尺寸
                    // 获取CameraDevice的尺寸信息
                    //CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(opened_camera.getId());
                    //StreamConfigurationMap streamConfigurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                    //Size previewSize = getAppropriatePreviewSize(streamConfigurationMap.getOutputSizes(SurfaceTexture.class));
                    // 设置SurfaceHolder的尺寸

                    //Log.d(TAG,"previewSize.getWidth()="+previewSize.getWidth()+"previewSize.getHeight()="+previewSize.getHeight());
                    // 设置 LayoutParams 来设置大小
                    textureView.getSurfaceTexture().setDefaultBufferSize(displayWidth/3*4,displayWidth);
                    ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(textureView.getWidth(), textureView.getWidth()*4/3);
                    textureView.setLayoutParams(layoutParams);

                    requestBuilder = opened_camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);//
                    requestBuilder.addTarget(texture_surface);

                    //requestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte) 100);
                    //目前看不设置是自动对焦的并且效果很好
                    //requestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
                    //requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);//CONTROL_AF_MODE_AUTO
                    //requestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
                    request = requestBuilder.build();
                    cam_capture_session_stateCallback=new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {
                            cameraCaptureSession=session;
                            try {
                                session.setRepeatingRequest(request,null,null);
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }
                        }
                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                        }
                    };

                    //B1. 准备工作:初始化ImageReader
                    imageReader = ImageReader.newInstance(1080/3*4  ,1080, ImageFormat.JPEG,2);
                    //B2. 准备工作:设置ImageReader收到图片后的回调函数
                    imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
                        @Override
                        public void onImageAvailable(ImageReader reader) {

                            //B2.1 接收图片:从ImageReader中读取最近的一张,转成Bitmap
                            Image image= reader.acquireLatestImage();
                            ByteBuffer buffer= image.getPlanes()[0].getBuffer();
                            int length= buffer.remaining();
                            byte[] bytes= new byte[length];
                            buffer.get(bytes);
                            image.close();
                            Bitmap bmp = BitmapFactory.decodeByteArray(bytes,0,length);
                            //矩阵变换后获取正向图像
                            Matrix matrix = new Matrix();
                            matrix.postRotate((90+mDeviceOrientation)% 360 * 1.0F);
                            bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, false);
                            //B2.2 显示图片
                            takephoto_imageView.setImageBitmap(bitmap);
                            String path = MainActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES).toString()+"/temp.jpg";
                            BitmapUtils.saveBitmap(bitmap,path);

                            //qwd add 记录拍照时传感器数据
                            System.arraycopy(degrees, 0, degreesWhenCapture, 0, degrees.length);

                            uploadImgToJS(path);
                        }
                    },null);
                    //B3 配置:获取ImageReader的Surface
                    imageReaderSurface = imageReader.getSurface();
                    opened_camera.createCaptureSession( Arrays.asList(texture_surface,imageReaderSurface), cam_capture_session_stateCallback,null);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void onDisconnected(@NonNull CameraDevice camera) {
            }
            @Override
            public void onError(@NonNull CameraDevice camera, int error) {
            }
        };
        checkPermission();
        try {
            cameraManager.openCamera(cameraManager.getCameraIdList()[0],cam_stateCallback,null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

//    private void setAutoFocus() {
//        try {
//            // 获取相机的CameraCaptureSession
//            cameraCaptureSession.setRepeatingRequest(buildFocusRequest(), null, null);
//        } catch (CameraAccessException e) {
//            e.printStackTrace();
//        }
//    }
    // 创建一个CaptureRequest用于自动对焦
//    private CaptureRequest buildFocusRequest() throws CameraAccessException {
//        CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
//        builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
//        builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
//        builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
//        return builder.build();
//    }


    private void checkPermission() {
        // 检查是否申请了权限
        if(ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED){
            if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)){

            }else{
                ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},1);
            }
        }
    }
    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "onResume");
        // 如果 textureView可用,就直接打开相机
        Log.d(TAG,"texture_surface:"+texture_surface);
        Log.d(TAG," imageReaderSurface:"+imageReaderSurface);
        if(textureView.isAvailable() && texture_surface!=null ){
            openCamera();
        }else{
            // 否则,就开启它的可用时监听。
            textureView.setSurfaceTextureListener(surfaceTextureListener);
        }
        myOrientationEventListener.enable();

        registerSensor();
    }
    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "onPause");
        myOrientationEventListener.disable();
        // 先把相机的session关掉
        if(cameraCaptureSession!=null){
            cameraCaptureSession.close();
        }
        // 再关闭相机
        if(null!=opened_camera){
            opened_camera.close();
        }
        // 最后关闭ImageReader
        if(null!=imageReader){
            imageReader.close();
        }
        // 最后交给父View去处理

        unregisterSensor();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 最后关闭ImageReader
        Log.i(TAG, "onDestroy");
//        if(null!=imageReader){
//            imageReader.close();
//        }
    }


    SensorManager sensorManager;
    Sensor magneticSensor;
    Sensor accelerometerSensor;
    Sensor orientationSensor;
    SensorEventListener sensorEventListener;
    float[] gravity = new float[3];//用来保存加速度传感器的值
    float[] geomagnetic = new float[3];//用来保存地磁传感器的值
    float[] rotationMatrix = new float[9];//
    float[] orientationValues = new float[3];//用来保存最终的结果

    double[] degrees = new double[3];
    double[] degreesWhenCapture = new double[3];
    private void initSensor(Context context){
        /**
         * 初始化传感器
         * */
        sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        //获取Sensor
        magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        orientationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);

        sensorEventListener = new SensorEventListener() {
            @Override
            public void onSensorChanged(SensorEvent event) {
                if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                    geomagnetic = event.values;
                }
                if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                    gravity = event.values;
                    // r从这里返回
                    SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic);
                    //values从这里返回
                    SensorManager.getOrientation(rotationMatrix, orientationValues);
                    //提取数据
                    double degreeZ = Math.toDegrees(orientationValues[0]);
                    double degreeX = Math.toDegrees(orientationValues[1]);
                    double degreeY = Math.toDegrees(orientationValues[2]);

                    degrees[0] = degreeZ;
                    degrees[1] = degreeX;
                    degrees[2] = degreeY;

                }
//                if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
//                    // 获取手机角度
//                    float angleZ = event.values[0]; // 这里的角度是指手机绕Z轴旋转的角度,0表示北,90表示东,180表示南,270表示西
//                    float angleX = event.values[1];
//                    float angleY = event.values[2];
//                    //Log.w(TAG,"angleX=" + angleX + "; angleY=" + angleY + "; angleZ=" + angleZ);
//                    // 根据需要处理角度信息
//                }
            }

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

            }
        };
    }

    void registerSensor(){
        sensorManager.registerListener(sensorEventListener, magneticSensor, SensorManager.SENSOR_DELAY_UI);
        sensorManager.registerListener(sensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_UI);
        sensorManager.registerListener(sensorEventListener,orientationSensor,SensorManager.SENSOR_DELAY_UI);
    }

    void unregisterSensor(){
        sensorManager.unregisterListener(sensorEventListener);

    }

    /**
     * 获取手机旋转角度
     */
    public void getOritation() {
        // r从这里返回
        SensorManager.getRotationMatrix(rotationMatrix, null, gravity, geomagnetic);
        //values从这里返回
        SensorManager.getOrientation(rotationMatrix, orientationValues);
        //提取数据
        double degreeZ = Math.toDegrees(orientationValues[0]);
        double degreeX = Math.toDegrees(orientationValues[1]);
        double degreeY = Math.toDegrees(orientationValues[2]);
//        if(listener != null){
//            listener.onOrientationChange(degreeX, degreeY, degreeZ);
//        }
        //Log.w(TAG,"degreeX=" + degreeX + "; degreeY=" + degreeY + "; degreeZ=" + degreeZ);
    }



    void uploadImgToJS(String filePath) {
        Logger.d(TAG, "filePath: " + filePath);
        String getAccessUrl = "http://47.100.2.19/upload";
        //1.创建MultipartBody.Builder对象
        MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);//表单类型
        //2.获取图片,创建请求体
        File file = new File(filePath);
        RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        //3.调用MultipartBody.Builder的addFormDataPart()方法添加表单数据
        builder.addFormDataPart("x", Double.toString(degreesWhenCapture[1]));
        builder.addFormDataPart("y", Double.toString(degreesWhenCapture[2]));
        builder.addFormDataPart("z", Double.toString(degreesWhenCapture[0]));
        builder.addFormDataPart("file", file.getName(), body); //添加图片数据,body创建的请求体
        //4.创建List<MultipartBody.Part> 集合,
        //  调用MultipartBody.Builder的build()方法会返回一个新创建的MultipartBody
        //  再调用MultipartBody的parts()方法返回MultipartBody.Part集合
        List<MultipartBody.Part> parts = builder.build().parts();
        XRetrofit.upload(getAccessUrl, parts, new StringCallBack() {
            @Override
            protected void onSuccess(String response) {
                Log.w(TAG,"onSuccess response="+response);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        showResponseDialog(response);
                    }
                });
            }

            @Override
            protected void onFail(String response) {
                Log.w(TAG,"onFail response="+response);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        showResponseDialog(response);
                    }
                });
            }
        });
    }

    void showResponseDialog(String response){

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("服务器的返回消息");
        builder.setMessage(response);
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            }
        });
        builder.setIcon(R.mipmap.ic_launcher);
        builder.show();
    }
}

布局代码如下

activity布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextureView
        android:id="@+id/texture_view_camera2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/image_view_preview_image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/btn_camera2_takephoto"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:text="拍照"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <FrameLayout
        android:id="@+id/root_frame_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"

        app:layout_constraintBottom_toTopOf="@+id/texture_view_camera2"
        app:layout_constraintEnd_toEndOf="@+id/texture_view_camera2"
        app:layout_constraintStart_toStartOf="@+id/texture_view_camera2"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

效果:

image.png