Camera旧版本使用

273 阅读19分钟

基于旧版本的Camera功能实现,分为几个部分

  • Camera管理类
  • 业务代码

实现效果(ps:放最前面,仅后置)

28971722481230_.pic.jpg 28981722481232_.pic.jpg 28991722481233_.pic.jpg

Camera管理类

ITPCameraManager

public class ITPCameraManager implements SensorEventListener {
    static private final String TAG = "CameraManager";
    static public final int DEFAULT_WIDTH = 1920;
    static public final int DEFAULT_HEIGHT = 1080;

    static public class CameraOpenFailedException extends Exception {
    }

    static public class Size {
        final private int width;
        final private int height;

        public Size(int width, int height) {
            this.width = width;
            this.height = height;
        }

        public int getWidth() {
            return width;
        }

        public int getHeight() {
            return height;
        }
    }

    public enum AspectRatio {
        ASPECT_RATIO_1_1,
        ASPECT_RATIO_4_3,
        ASPECT_RATIO_16_9,
        ASPECT_RATIO_18_9,
        ASPECT_RATIO_AS_SCREEN
    }

    public enum PreviewMode {
        PREVIEW_MODE_PICTURE,
        PREVIEW_MODE_VIDEO
    }

    public enum RotationMode {
        ROTATION_WITH_SENSOR,
        ROTATION_WITH_ACTIVITY
    }

    private boolean isInited = false;
    private int frontCameraId = -1;
    private int backCameraId = -1;
    private SparseArray<Camera.CameraInfo> cameraInfoMap = new SparseArray<>(2);
    private CameraWrap currentCamera;
    private MediaRecorder mediaRecorder;
    private boolean isRecording = false;
    private SensorManager sensorManager;
    private Sensor accelerometerSensor;
    private int sensorOrientation = 0;
    private RotationMode rotationMode = RotationMode.ROTATION_WITH_SENSOR;

    public static ITPCameraManager createInstance() {
        return new ITPCameraManager();
    }

    private ITPCameraManager() {
    }

    private ITPCameraView mCameraView;

    public void init(ITPCameraView cameraView) {
        mCameraView = cameraView;
        if (!isInited()) {
            initCameraInfo();
            isInited = true;
        }

        sensorManager = (SensorManager) BContext.context().getSystemService(Context.SENSOR_SERVICE);
        if (sensorManager != null) {
            accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_UI);
        }
    }

    public void unInit() {
        if (currentCamera != null) {
            currentCamera.close();
            currentCamera = null;
        }
        cameraInfoMap.clear();

        if (sensorManager != null) {
            sensorManager.unregisterListener(this);
        }

        isInited = false;
    }

    public boolean isInited() {
        return isInited;
    }

    private void initCameraInfo() {
        try {
            Logger.i(TAG, "camera count = " + Camera.getNumberOfCameras());
            for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
                Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
                Camera.getCameraInfo(i, cameraInfo);
                if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                    frontCameraId = i;
                    cameraInfoMap.put(frontCameraId, cameraInfo);
                    Logger.i(TAG, "front camera id = " + i);
                } else if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    //避免后置多摄像头id将主摄像头id覆盖
                    if (backCameraId != -1) {
                        continue;
                    }
                    backCameraId = i;
                    cameraInfoMap.put(backCameraId, cameraInfo);
                    Logger.i(TAG, "rear camera id = " + i);
                }
            }


        } catch (Throwable e) {
            Logger.e(TAG, e);
        }
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event == null || event.sensor != accelerometerSensor) {
            return;
        }

        float x = -event.values[0];
        float y = -event.values[1];
        float z = -event.values[2];
        float magnitude = x * x + y * y;

        if (magnitude * 4 >= z * z) {
            float OneEightyOverPi = 57.29577957855f;
            float angle = (float) Math.atan2(-y, x) * OneEightyOverPi;
            int orientation = 90 - Math.round(angle);

            while (orientation >= 360) {
                orientation -= 360;
            }

            while (orientation < 0) {
                orientation += 360;
            }

            if (orientation > 45 && orientation < 135) {
                this.sensorOrientation = 90;
            } else if (orientation > 135 && orientation < 225) {
                this.sensorOrientation = 180;
            } else if (orientation > 225 && orientation < 315) {
                this.sensorOrientation = 270;
            } else {
                this.sensorOrientation = 0;
            }
        }
    }

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

    public int getFrontCameraId() {
        return frontCameraId;
    }

    public int getBackCameraId() {
        return backCameraId;
    }

    private CameraWrap setCurrentCamera(CameraWrap camera) {
        this.currentCamera = camera;
        return this.currentCamera;
    }

    public CameraWrap getCurrentCamera() {
        return currentCamera;
    }

    public int getCurrentCameraId() {
        if (currentCamera != null) {
            return currentCamera.getCameraId();
        }
        return backCameraId;
    }

    public void toggleCamera() {
        if (getCurrentCamera() == null || isRecording) {
            return;
        }

        try {
            boolean isPreviewing = getCurrentCamera().isPreviewing();
            CameraWrap currentCameraValue = getCurrentCamera();
            currentCameraValue.close();
            setCurrentCamera(new CameraWrap(currentCameraValue.getCameraId() == getFrontCameraId() ? getBackCameraId() : getFrontCameraId()).inherit(currentCameraValue));

            if (isPreviewing) {
                getCurrentCamera().startPreview(getCurrentCamera().previewActivity);
            }
        } catch (Throwable e) {
            Logger.e(TAG, e);
        }
    }

    public boolean restoreCameraIfNeed() {
        if (getCurrentCamera() == null || isRecording) {
            return false;
        }

        try {
            boolean isPreviewing = getCurrentCamera().isPreviewing();
            if (!isPreviewing) {
                return false;
            }
            CameraWrap currentCameraValue = getCurrentCamera();
            currentCameraValue.close();
            setCurrentCamera(new CameraWrap(currentCameraValue.getCameraId()).inherit(currentCameraValue));

            if (isPreviewing) {
                getCurrentCamera().startPreview(getCurrentCamera().previewActivity);
            }

            return true;
        } catch (Throwable e) {
            Logger.e(TAG, e);
        }
        return false;
    }

    public final CameraWrap open(int cameraId) throws CameraOpenFailedException {
        if (getCurrentCamera() != null && getCurrentCamera().getRawCamera() != null) {
            return getCurrentCamera();
        }

        CameraWrap cameraWrap = new CameraWrap(cameraId);
        cameraWrap.getRawCamera().getParameters();
        return setCurrentCamera(cameraWrap);
    }

    @SuppressWarnings({"unused", "UnusedReturnValue"})
    public class CameraWrap {
        private Camera camera;
        private int id;
        private Activity previewActivity;
        private boolean hasError = false;
        private SurfaceTexture surfaceTexture;
        private AspectRatio aspectRatio = null;
        private Size previewSize = null;
        private Size pictureSize = null;
        private Size mVideoSize = null;
        private int desiredPixels = DEFAULT_WIDTH * DEFAULT_HEIGHT;

        private CameraWrap(int id) throws CameraOpenFailedException {
            try {
                Logger.i(TAG, "current camera id = " + id);
                this.camera = Camera.open(id);
            } catch (Exception e) {
                Logger.e(TAG, e);
                throw new CameraOpenFailedException();
            }
            this.id = id;

            if (camera == null) {
                hasError = true;
                return;
            }

            try {
                Camera.Parameters parameters = camera.getParameters();

                if (Build.VERSION.SDK_INT > 14 && parameters.isVideoStabilizationSupported()) {
                    parameters.setVideoStabilization(true);
                }

                parameters.setPreviewFormat(ImageFormat.NV21);
                camera.setParameters(parameters);
            } catch (Exception e) {
                Logger.e(TAG, e);
            } catch (Throwable e) {
                hasError = true;
                Logger.e(TAG, e);
            }
        }

        public Camera getRawCamera() {
            return camera;
        }

        public int getCameraId() {
            return id;
        }

        public boolean hasError() {
            return hasError;
        }

        public void close() {
            if (camera == null) {
                return;
            }

            try {
                if (getCurrentCamera() == this) {
                    setCurrentCamera(null);
                }

                if (isRecording()) {
                    stopRecordVideo();
                }

                camera.setPreviewCallback(null);
                camera.stopPreview();
                camera.lock();
                camera.release();
                camera = null;
            } catch (Exception e) {
                Logger.e(TAG, e);
            } catch (Throwable e) {
                Logger.e(TAG, e);
            }
        }

        public CameraWrap inherit(CameraWrap camera) {
            previewActivity = camera.previewActivity;
            surfaceTexture = camera.surfaceTexture;
            aspectRatio = camera.aspectRatio;
            previewSize = camera.previewSize;
            pictureSize = camera.pictureSize;
            mVideoSize = camera.mVideoSize;
            desiredPixels = camera.desiredPixels;
            camera.previewActivity = null;
            camera.surfaceTexture = null;
            camera.aspectRatio = null;
            camera.previewSize = null;
            camera.pictureSize = null;
            camera.mVideoSize = null;
            camera.desiredPixels = DEFAULT_WIDTH * DEFAULT_HEIGHT;
            return this;
        }

        public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
            this.surfaceTexture = surfaceTexture;

            try {
                if (camera != null) {
                    camera.setPreviewTexture(surfaceTexture);
                }
            } catch (IOException e) {
                Logger.e(TAG, e);
            }
        }

        public SurfaceTexture getSurfaceTexture() {
            return surfaceTexture;
        }

        public boolean startPreview(Activity activity) {
            if (camera == null || activity == null) {
                return false;
            }

            try {
                previewActivity = activity;
                updateCameraDisplayOrientation();

                Camera.Parameters parameters = camera.getParameters();

                Size previewSizeValue = getPreviewSize();
                parameters.setPreviewSize(previewSizeValue.width, previewSizeValue.height);
/*                Size pictureSize = getPictureSize();
                parameters.setPictureSize(pictureSize.width, pictureSize.height);*/

                camera.setParameters(parameters);

                if (surfaceTexture != null) {
                    camera.setPreviewTexture(surfaceTexture);
                }

                camera.startPreview();
                return true;
            } catch (Throwable e) {
                Logger.e(TAG, e);
                hasError = true;
                return false;
            }
        }

        public boolean stopPreview() {
            if (camera == null) {
                return false;
            }

            try {
                camera.stopPreview();
                previewActivity = null;
                return true;
            } catch (Throwable e) {
                Logger.e(TAG, e);
                hasError = true;
                return false;
            }
        }

        public boolean isPreviewing() {
            return previewActivity != null;
        }

        public void setPreviewSize(Size previewSize) {
            this.previewSize = previewSize;

            if (camera != null) {
                Camera.Parameters parameters = camera.getParameters();
                previewSize = getPreviewSize();
                parameters.setPreviewSize(previewSize.getWidth(), previewSize.height);
                camera.setParameters(parameters);
            }
        }

        public Size getPreviewSize() {
            try {
                if (previewSize != null) {
                    return previewSize;
                } else if (aspectRatio != null && camera != null) {
                    return matchAspectRatio(camera.getParameters().getSupportedPreviewSizes(), aspectRatio);
                } else {
                }
                return new Size(DEFAULT_WIDTH, DEFAULT_HEIGHT);
            } catch (Exception e) {

            }
            return new Size(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        }

        public void setPictureSize(Size pictureSize) {
            this.pictureSize = pictureSize;

            if (camera != null) {
                Camera.Parameters parameters = camera.getParameters();
                pictureSize = getPictureSize();
                parameters.setPictureSize(pictureSize.width, pictureSize.height);
                camera.setParameters(parameters);
            }
        }

        public Size getPictureSize() {
            if (pictureSize != null) {
                return pictureSize;
            } else if (aspectRatio != null && camera != null) {
                return matchAspectRatio(camera.getParameters().getSupportedPictureSizes(), aspectRatio);
            } else {
                return new Size(DEFAULT_WIDTH, DEFAULT_HEIGHT);
            }
        }

        public void setVideoSize(Size videoSize) {
            this.mVideoSize = videoSize;
        }

        public Size getVideoSize() {

            Camera.Parameters parameters = camera.getParameters();
            List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
            List<Camera.Size> mSupportedVideoSizes = parameters.getSupportedVideoSizes();

            boolean isPad = DeviceInfo.isPadDevice(BContext.context());
            Camera.Size optimalSize = getOptimalVideoSize(mSupportedVideoSizes,
                    mSupportedPreviewSizes, mCameraView.getWidth(), mCameraView.getHeight());
            if (isPad && optimalSize != null) {
                return new Size(optimalSize.width, optimalSize.height);
            } else if (mVideoSize != null) {
                return mVideoSize;
            } else if (aspectRatio != null) {
                return matchAspectRatio(camera.getParameters().getSupportedVideoSizes(), aspectRatio);
            } else {
                return new Size(DEFAULT_WIDTH, DEFAULT_HEIGHT);
            }
        }

        public void setAspectRatio(AspectRatio aspectRatio) {
            this.aspectRatio = aspectRatio;

            if (camera != null) {
                Camera.Parameters parameters = camera.getParameters();

                if (previewSize == null) {
                    Size previewSizeValue = getPreviewSize();
                    parameters.setPreviewSize(previewSizeValue.width, previewSizeValue.height);
                    camera.setParameters(parameters);
                }

/*                if (pictureSize == null) {
                    Size pictureSize = getPictureSize();
                    parameters.setPictureSize(pictureSize.width, pictureSize.height);
                    camera.setParameters(parameters);
                }*/
            }
        }

        private Size matchAspectRatio(List<Camera.Size> supportedSizes, AspectRatio aspectRatio) {
            Size matchedSize = null;
            Size compromisedSize = null;
            for (Camera.Size size : supportedSizes) {
                if (matchedSize == null || Math.abs(matchedSize.width * matchedSize.height - desiredPixels) > Math.abs(size.width * size.height - desiredPixels)) {
                    if (isMatchAspectRatio(size.width, size.height, aspectRatio)) {
                        matchedSize = new Size(size.width, size.height);
                    }
                }

                if (compromisedSize == null || Math.abs(compromisedSize.width * compromisedSize.height - desiredPixels) > Math.abs(size.width * size.height - desiredPixels)) {
                    compromisedSize = new Size(size.width, size.height);
                }
            }

            return matchedSize == null ? compromisedSize : matchedSize;
        }

        /**
         * Iterate over supported camera video sizes to see which one best fits the
         * dimensions of the given view while maintaining the aspect ratio. If none can,
         * be lenient with the aspect ratio.
         *
         * @param supportedVideoSizes Supported camera video sizes.
         * @param previewSizes        Supported camera preview sizes.
         * @param w                   The width of the view.
         * @param h                   The height of the view.
         * @return Best match camera video size to fit in the view.
         */
        public Camera.Size getOptimalVideoSize(List<Camera.Size> supportedVideoSizes,
                                               List<Camera.Size> previewSizes, int w, int h) {
            // Use a very small tolerance because we want an exact match.
            final double ASPECT_TOLERANCE = 0.1;
            double targetRatio = (double) w / h;

            // Supported video sizes list might be null, it means that we are allowed to use the preview
            // sizes
            List<Camera.Size> videoSizes;
            if (supportedVideoSizes != null) {
                videoSizes = supportedVideoSizes;
            } else {
                videoSizes = previewSizes;
            }
            Camera.Size optimalSize = null;

            // Start with max value and refine as we iterate over available video sizes. This is the
            // minimum difference between view and camera height.
            double minDiff = Double.MAX_VALUE;

            // Target view height
            int targetHeight = h;

            // Try to find a video size that matches aspect ratio and the target view size.
            // Iterate over all available sizes and pick the largest size that can fit in the view and
            // still maintain the aspect ratio.
            for (Camera.Size size : videoSizes) {
                double ratio = (double) size.width / size.height;
                if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                    continue;
                if (Math.abs(size.height - targetHeight) < minDiff && previewSizes.contains(size)) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }

            // Cannot find video size that matches the aspect ratio, ignore the requirement
            if (optimalSize == null) {
                minDiff = Double.MAX_VALUE;
                for (Camera.Size size : videoSizes) {
                    if (Math.abs(size.height - targetHeight) < minDiff && previewSizes.contains(size)) {
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                    }
                }
            }
            return optimalSize;
        }

        private boolean isMatchAspectRatio(int width, int height, AspectRatio aspectRatioExpected) {
            double aspectRatioValue = isCameraPortrait() ? (double) height / width :
                    (double) width / height;

            switch (aspectRatioExpected) {
                case ASPECT_RATIO_1_1: {
                    return aspectRatioValue == 1;
                }
                case ASPECT_RATIO_4_3: {
                    return Math.abs(aspectRatioValue - (4D / 3)) < 0.01D;
                }
                case ASPECT_RATIO_16_9: {
                    return Math.abs(aspectRatioValue - (16D / 9)) < 0.01D;
                }
                case ASPECT_RATIO_18_9: {
                    return Math.abs(aspectRatioValue - (18D / 9)) < 0.01D;
                }
                case ASPECT_RATIO_AS_SCREEN: {
                    DisplayMetrics displayMetrics = new DisplayMetrics();
                    try {
                        Class.forName("android.view.Display").getMethod("getRealMetrics", DisplayMetrics.class).invoke(
                                ((WindowManager) Objects.requireNonNull(BContext.context().getSystemService(Context.WINDOW_SERVICE))).getDefaultDisplay(), displayMetrics);
                        return Math.abs(aspectRatioValue - ((double) displayMetrics.heightPixels / displayMetrics.widthPixels)) < 0.01D;
                    } catch (Throwable e) {
                        Logger.e(TAG, e);
                        return isMatchAspectRatio(width, height, AspectRatio.ASPECT_RATIO_16_9);
                    }
                }
            }

            return false;
        }

        public void setDesiredPixels(int desiredPixels) {
            this.desiredPixels = desiredPixels;
        }

        public boolean isCameraPortrait() {
            Camera.CameraInfo cameraInfo = cameraInfoMap.get(id);
            return cameraInfo != null && cameraInfo.orientation % 180 == 0;
        }

        public void zoom(int change) {
            if (camera == null) {
                return;
            }

            Camera.Parameters parameters = camera.getParameters();
            if (!parameters.isZoomSupported()) {
                return;
            }

            int currentZoomValue = parameters.getZoom();
            int maxZoomValue = parameters.getMaxZoom();
            int newZoomValue = currentZoomValue + change;

            if (newZoomValue < 0) {
                newZoomValue = 0;
            } else if (newZoomValue > maxZoomValue) {
                newZoomValue = maxZoomValue;
            }

            parameters.setZoom(newZoomValue);
            camera.setParameters(parameters);
        }

        public boolean setFlashMode(String flashMode) {
            if (camera == null) {
                return false;
            }

            try {
                Camera.Parameters parameters = camera.getParameters();
                parameters.setFlashMode(flashMode);
                camera.setParameters(parameters);
                return true;
            } catch (Throwable e) {
                Logger.e(TAG, e);
                return false;
            }
        }

        public String getFlashMode() {
            if (camera == null) {
                return null;
            }

            try {
                Camera.Parameters parameters = camera.getParameters();
                return parameters.getFlashMode();
            } catch (Throwable e) {
                Logger.e(TAG, e);
                return null;
            }
        }

        public void updateCameraDisplayOrientation() {
            if (camera == null || previewActivity == null || previewActivity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && previewActivity.isDestroyed())) {
                return;
            }
            try {
                camera.setDisplayOrientation(getCameraOrientationActivity(previewActivity));
            } catch (Exception e) {
                Logger.e(TAG, e);
            }
        }

        private int getCameraOrientationActivity(final Activity activity) {
            int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
            int degrees = 0;
            switch (rotation) {
                case Surface.ROTATION_0:
                    degrees = 0;
                    break;
                case Surface.ROTATION_90:
                    degrees = 90;
                    break;
                case Surface.ROTATION_180:
                    degrees = 180;
                    break;
                case Surface.ROTATION_270:
                    degrees = 270;
                    break;
            }

            int result;
            Camera.CameraInfo cameraInfo = cameraInfoMap.get(id);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                result = (cameraInfo.orientation + degrees) % 360;
                result = (360 - result) % 360;
            } else {
                result = (cameraInfo.orientation - degrees + 360) % 360;
            }
            return result;
        }

        public int getCameraOrientationSensor() {
            int rotation;
            int orientation = (sensorOrientation + 45) / 90 * 90;
            Camera.CameraInfo cameraInfo = cameraInfoMap.get(id);
            if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                rotation = (cameraInfo.orientation - orientation + 360) % 360;
            } else {
                rotation = (cameraInfo.orientation + orientation) % 360;
            }
            return rotation;
        }

        public void setJpegQuality(int quality) {
            if (camera == null) {
                return;
            }

            Camera.Parameters parameters = camera.getParameters();
            parameters.setJpegQuality(quality);
            camera.setParameters(parameters);
        }

        public int getJpegQuality() {
            if (camera == null) {
                return -1;
            }

            Camera.Parameters parameters = camera.getParameters();
            return parameters.getJpegQuality();
        }

        public void setFocusMode(String focusMode) {
            if (camera == null) {
                return;
            }

            Camera.Parameters parameters = camera.getParameters();
            parameters.setFocusMode(focusMode);
            camera.setParameters(parameters);
        }

        public String getFocusMode() {
            if (camera == null) {
                return "";
            }

            Camera.Parameters parameters = camera.getParameters();
            return parameters.getFocusMode();
        }

        public void setRecordingHint(boolean hint) {
            CameraCompat.setRecordingHint(camera, hint);
        }

        public void takePicture(Camera.PictureCallback callback) {
            if (camera == null || !isPreviewing()) {
                return;
            }

            try {
                Camera.Parameters parameters = camera.getParameters();
                parameters.setRotation(getCameraOrientationSensor());
                camera.setParameters(parameters);
                camera.takePicture(null, null, (bytes, camera) -> {
                    callback.onPictureTaken(bytes, camera);
                    camera.startPreview();
                });
            } catch (Throwable e) {
                Logger.e(TAG, e);
            }
        }

        public void takePictureByPreview(Camera.PictureCallback callback) {
            if (camera == null || !isPreviewing()) {
                Logger.e(TAG, "%s", "take picture by preview camera == null || previewing=false");
                return;
            }

            try {
                Camera.Parameters parameters = camera.getParameters();
                parameters.setRotation(getCameraOrientationSensor());
                camera.setParameters(parameters);
                // 自动聚焦
                camera.cancelAutoFocus();
                Logger.i(TAG, "takePicture AutoFocus  start");
                camera.autoFocus(new Camera.AutoFocusCallback() {
                    @Override
                    public void onAutoFocus(boolean success, Camera camera) {
                        Logger.i(TAG, "%s", "take picture by preview on auto focus success=" + success);
                        camera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
                            @Override
                            public void onPreviewFrame(byte[] data, Camera camera) {
                                ThreadUtil.execOnNewThread(() -> {
                                    Camera.Size size = camera.getParameters().getPreviewSize(); //获取预览大小
                                    Logger.i(TAG, "%s", "take picture by preview on preview frame data length=" + (data == null ? 0 : data.length) + " width=" + size.width + " height=" + size.height);
                                    // YUV数据处理成jpeg数据
                                    byte[] jpegData = YuvUtils.compressToJpeg(data, ImageFormat.NV21, size.width, size.height, getCameraOrientationSensor());
                                    if (callback != null) {
                                        callback.onPictureTaken(jpegData, camera);
                                    }
                                });
                            }
                        });
                    }
                });
            } catch (Throwable e) {
                Logger.e(TAG, e);
            }
        }
        
        public void takePictureByPreviewNoFocus(Camera.PictureCallback callback) {
            if (camera == null || !isPreviewing()) {
                Logger.e(TAG, "%s", "take picture by preview camera == null || previewing=false");
                return;
            }

            try {
                Camera.Parameters parameters = camera.getParameters();
                parameters.setRotation(getCameraOrientationSensor());
                camera.setParameters(parameters);
                // 自动聚焦
//                camera.cancelAutoFocus();
                Logger.i(TAG, "takePicture AutoFocus  start");
                camera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
                    @Override
                    public void onPreviewFrame(byte[] data, Camera camera) {
                        ThreadUtil.execOnNewThread(() -> {
                            Camera.Size size = camera.getParameters().getPreviewSize(); //获取预览大小
                            Logger.i(TAG, "%s", "take picture by preview on preview frame data length=" + (data == null ? 0 : data.length) + " width=" + size.width + " height=" + size.height);


                            // YUV数据处理成jpeg数据
                            byte[] jpegData = YuvUtils.compressToJpeg(data, ImageFormat.NV21, size.width, size.height, getCameraOrientationSensor());
                            if (callback != null) {
                                callback.onPictureTaken(jpegData, camera);
                            }
                        });
                    }
                });
            } catch (Throwable e) {
                Logger.e(TAG, e);
            }
        }

        public void takePictureByPreview(boolean focus, Camera.PictureCallback callback) {
            if (camera == null || !isPreviewing()) {
                Logger.e(TAG, "%s", "take picture by preview camera == null || previewing=false");
                return;
            }

            try {
                Camera.Parameters parameters = camera.getParameters();
                parameters.setRotation(getCameraOrientationSensor());
                camera.setParameters(parameters);
                boolean supportFocus = parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO);
                Logger.i(TAG, "supportFocus: " + supportFocus);
                if (supportFocus) {
                    camera.cancelAutoFocus(); // 自动聚焦
                    camera.autoFocus(new Camera.AutoFocusCallback() {
                        @Override
                        public void onAutoFocus(boolean success, Camera camera) {
                            Logger.i(TAG, "%s", "take picture by preview on auto focus success=" + success);
                            setOneShotPreviewCallback(camera, callback);
                        }
                    });
                } else {
                    setOneShotPreviewCallback(camera, callback);
                }
            } catch (Throwable e) {
                Logger.e(TAG, e);
            }
        }

        public void takePictureByPreviewCompatRealme10(boolean focus, Camera.PictureCallback callback) {

            if (camera == null || !isPreviewing()) {
                Logger.e(TAG, "%s", "take picture by preview camera == null || previewing=false");
                return;
            }
            Logger.i(TAG, "take picture :  focus before ");
            try {
                Camera.Parameters parameters = camera.getParameters();
                parameters.setRotation(getCameraOrientationSensor());
                camera.setParameters(parameters);
                if (focus) {
                    camera.cancelAutoFocus(); // 自动聚焦
                    camera.autoFocus(new Camera.AutoFocusCallback() {
                        @Override
                        public void onAutoFocus(boolean success, Camera camera) {
                            Logger.i(TAG, "%s", "take picture by preview on auto focus success=" + success);
                            setOneShotPreviewCallback(camera, callback);
                        }
                    });
                } else {
                    Logger.i(TAG, "take picture :  start without focus ");
                    setOneShotPreviewCallback(camera, callback);
                }
            } catch (Throwable e) {
                Logger.e(TAG, e);
            }
        }

        private void setOneShotPreviewCallback(Camera camera, Camera.PictureCallback callback) {
            if (camera == null || callback == null) {
                Logger.i(TAG, "camera is null or callback is null.");
                return;
            }
            camera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    ThreadUtil.execOnNewThread(() -> {
                        Camera.Size size = camera.getParameters().getPreviewSize(); //获取预览大小


                        //11
                        Logger.i(TAG, "%s", "take picture by preview on preview frame data length=" + (data == null ? 0 : data.length) + " width=" + size.width + " height=" + size.height);
                        // YUV数据处理成jpeg数据
                        byte[] jpegData = YuvUtils.compressToJpeg(data, ImageFormat.NV21, size.width, size.height, getCameraOrientationSensor());
                        if (callback != null) {
                            callback.onPictureTaken(jpegData, camera);
                        }
                    });
                }
            });
        }

        public boolean startRecordVideo(File file, MediaRecorder.OnErrorListener errorListener) {
            if (camera == null || !isPreviewing()) {
                return false;
            }

            if (isRecording()) {
                return true;
            }

            try {
                mediaRecorder = new MediaRecorder();
                Size videoSize = getVideoSize();
                camera.unlock();
                mediaRecorder.setCamera(camera);
                boolean hasAudioRecordPermission = PermissionsUtil.checkSelfPermission(BContext.context(), new String[]{Manifest.permission.RECORD_AUDIO}).isEmpty();
                if (hasAudioRecordPermission) {
                    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
                }
                mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                if (hasAudioRecordPermission) {
                    mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                }

                mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);

                //honor v20手机
                if ((LXUtil.isHonorV20()) && CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P)) {
                    CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_1080P);
                    if (profile != null) {
                        mediaRecorder.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
                    } else {
                        mediaRecorder.setVideoSize(videoSize.width, videoSize.height);
                    }
                } else {
                    mediaRecorder.setVideoSize(videoSize.width, videoSize.height);
                }

                mediaRecorder.setVideoEncodingBitRate(3 * 1024 * 1024);
                mediaRecorder.setOrientationHint(getCameraOrientationSensor());
                mediaRecorder.setOutputFile(file.getAbsolutePath());
                mediaRecorder.setMaxDuration(0);
                mediaRecorder.setOnErrorListener((mr, what, extra) -> {
                    Logger.e(TAG, "MediaRecorder onError, what = " + what + ", extra = " + extra);
                    stopRecordVideo();
                    if (errorListener != null) {
                        errorListener.onError(mr, what, extra);
                    }
                });
                mediaRecorder.setOnInfoListener((mr, what, extra) -> Logger.v(TAG, "MediaRecorder onInfo, what = " + what + ", extra = " + extra));
                mediaRecorder.prepare();
                mediaRecorder.start();

                isRecording = true;
                return true;
            } catch (Throwable e) {
                Logger.e(TAG, e);
                try {
                    camera.lock();
                } catch (Exception exception) {
                    Logger.e(TAG, e);
                }
                stopRecordVideo();
                return false;
            }
        }

        public void stopRecordVideo() {
            if (!isRecording()) {
                return;
            }

            try {
                mediaRecorder.stop();
                mediaRecorder.reset();
                mediaRecorder.release();
                camera.lock();
            } catch (Exception e) {
                Logger.e(TAG, e);
            } catch (Throwable e) {
                Logger.e(TAG, e);
            }
            mediaRecorder = null;
            isRecording = false;
        }

        public boolean isRecording() {
            return isRecording;
        }


    }

    /**
     * 获取手机型号
     *
     * @return 手机型号
     */
    public static String getSystemModel() {
        return Build.MODEL;
    }

    public static String getDeviceBrand() {
        return Build.BRAND;
    }

}

ITPCameraView

@SuppressWarnings("unused")
public class ITPCameraView extends TextureView {
    final private static String TAG = "ITPCameraView";
    private ITPCameraManager cameraManager = ITPCameraManager.createInstance();
    private int surfaceWidth = -1;
    private int surfaceHeight = -1;
    private ITPCameraManager.AspectRatio aspectRatio = null;
    private ITPCameraManager.Size previewSize = null;
    private ITPCameraManager.Size pictureSize = null;
    private ITPCameraManager.Size videoSize = null;
    private String focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
    private String flashMode = Camera.Parameters.FLASH_MODE_AUTO;
    private SurfaceTextureListener surfaceTextureListener;
    private boolean mbFull;

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

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

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

    public void init() {
        cameraManager.init(this);
        setSurfaceTextureListener();
    }

    public void init(boolean bFull) {
        mbFull = bFull;
        cameraManager.init(this);
        setSurfaceTextureListener();
    }

    public void unInit() {
        cameraManager.unInit();
    }

    private void setSurfaceTextureListener() {
        super.setSurfaceTextureListener(new SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                try {
                    surfaceWidth = width;
                    surfaceHeight = height;

                    ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
                    if (camera != null) {
                        if (camera.getSurfaceTexture() == null) {
                            camera.setSurfaceTexture(surface);
                        }

                        if (camera.isPreviewing()) {
                            updateTextureMatrix(width, height, camera.getPreviewSize(), camera.isCameraPortrait());
                        }
                    }

                    if (surfaceTextureListener != null) {
                        surfaceTextureListener.onSurfaceTextureAvailable(surface, width, height);
                    }
                } catch (Throwable e) {
                    Logger.e(TAG, e);
                }
            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
                surfaceWidth = width;
                surfaceHeight = height;

                ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
                if (camera != null && camera.isPreviewing()) {
                    updateTextureMatrix(width, height, camera.getPreviewSize(), camera.isCameraPortrait());
                }

                if (surfaceTextureListener != null) {
                    surfaceTextureListener.onSurfaceTextureSizeChanged(surface, width, height);
                }
            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                if (cameraManager.getCurrentCamera() != null) {
                    cameraManager.getCurrentCamera().close();
                }

                return surfaceTextureListener == null || surfaceTextureListener.onSurfaceTextureDestroyed(surface);
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {
                if (surfaceTextureListener != null) {
                    surfaceTextureListener.onSurfaceTextureUpdated(surface);
                }
            }
        });
    }

    public void setSurfaceTextureListener(SurfaceTextureListener surfaceTextureListener) {
        this.surfaceTextureListener = surfaceTextureListener;
    }

    public boolean startPreview() {
        return startPreview(false);
    }

    public boolean startPreview(boolean front) {
        try {
            ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
            if (camera == null) {
                if (front) {
                    camera = cameraManager.open(cameraManager.getFrontCameraId());
                } else {
                    camera = cameraManager.open(cameraManager.getCurrentCameraId());
                }
            }

            if (camera.isPreviewing()) {
                return true;
            }

            if (getSurfaceTexture() != null) {
                camera.setSurfaceTexture(getSurfaceTexture());
            }

            camera.setAspectRatio(aspectRatio);
            camera.setPreviewSize(previewSize);
            //camera.setPictureSize(pictureSize);
            camera.setVideoSize(videoSize);
            try {
                camera.setFocusMode(focusMode);
            } catch (Throwable e) {
                Logger.e(TAG, e);
            }

            try {
                camera.setFlashMode(flashMode);
            } catch (Throwable e) {
                Logger.e(TAG, e);
            }

            camera.setRecordingHint(true);
            camera.startPreview((Activity) getContext());

            if (surfaceWidth != -1 && surfaceHeight != -1) {
                updateTextureMatrix(surfaceWidth, surfaceHeight, camera.getPreviewSize(), camera.isCameraPortrait());
            }

            return true;
        } catch (Throwable e) {
            Logger.e(TAG, e);
            return false;
        }
    }

    public void stopPreview() {
        try {
            ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
            if (camera != null) {
                camera.stopPreview();
            }
        } catch (Throwable e) {
            Logger.e(TAG, e);
        }
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera != null) {
            camera.updateCameraDisplayOrientation();
        }
    }

    private int getDisplayRotation() {
        Display display = ((Activity) getContext()).getWindowManager().getDefaultDisplay();
        return display.getRotation();
    }

    private boolean isDisplayPortrait() {
        int displayRotation = getDisplayRotation();
        return displayRotation == ROTATION_0 || displayRotation == ROTATION_180;
    }

    @SuppressWarnings("SuspiciousNameCombination")
    private void updateTextureMatrix(int surfaceWidth, int surfaceHeight, ITPCameraManager.Size cameraPreviewSize, boolean isCameraPortrait) {
        if (surfaceWidth == 0 || surfaceHeight == 0 || cameraPreviewSize == null || cameraPreviewSize.getWidth() == 0 || cameraPreviewSize.getHeight() == 0) {
            return;
        }

        int previewWidth = cameraPreviewSize.getWidth();
        int previewHeight = cameraPreviewSize.getHeight();
        if (isDisplayPortrait() != isCameraPortrait) {
            previewHeight ^= previewWidth;
            previewWidth ^= previewHeight;
            previewHeight ^= previewWidth;
        }

        float surfaceAspectRatio = (float) surfaceHeight / surfaceWidth;
        float previewAspectRatio = (float) previewHeight / previewWidth;

        Logger.i(TAG, "updateTextureMatrix previewAspectRatio > surfaceAspectRatio = " + (previewAspectRatio > surfaceAspectRatio) + ";mbFull = " + mbFull);

        if (previewAspectRatio > surfaceAspectRatio && !LXUtil.adapterPhone() && !Device.isPad(getContext())) {
            Matrix matrix = new Matrix();
            if (!mbFull) {
                float scaleFactor = (float) surfaceHeight / previewHeight;
                float scaledPreviewWidth = previewWidth * scaleFactor;
                float scaleX = scaledPreviewWidth / surfaceWidth;
                if (cameraManager.getCurrentCameraId() == cameraManager.getFrontCameraId()) {
                    matrix.preScale(scaleX, 1, surfaceWidth / 2f, 0);
                    matrix.preTranslate(0, 0);
                } else {
                    matrix.preScale(scaleX, 1);
                    matrix.preTranslate((surfaceWidth - scaledPreviewWidth) / 2, 0);
                }
            } else {
                matrix.preTranslate(0, 0);
            }
            setTransform(matrix);
        } else {
            Matrix matrix = new Matrix();
            if (!mbFull) {
                float scaleFactor = (float) surfaceWidth / previewWidth;
                float scaledPreviewHeight = previewHeight * scaleFactor;
                float scaleY = scaledPreviewHeight / surfaceHeight;
                if (cameraManager.getCurrentCameraId() == cameraManager.getFrontCameraId()) {
                    matrix.preScale(1, scaleY, surfaceWidth / 2f, 0);
                    matrix.preTranslate(0, 0);
                } else {
                    matrix.preScale(1, scaleY);
                    matrix.preTranslate(0, (surfaceHeight - scaledPreviewHeight) / 2);
                }
            } else {
                matrix.preTranslate(0, 0);
            }
            setTransform(matrix);
        }
    }

    public void setAspectRatio(ITPCameraManager.AspectRatio aspectRatio) {
        this.aspectRatio = aspectRatio;
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera != null) {
            camera.setAspectRatio(aspectRatio);
            if (camera.isPreviewing()) {
                updateTextureMatrix(surfaceWidth, surfaceHeight, camera.getPreviewSize(), camera.isCameraPortrait());
            }
        }
    }

    public ITPCameraManager.AspectRatio getAspectRatio() {
        return aspectRatio;
    }

    public void setPreviewSize(ITPCameraManager.Size previewSize) {
        this.previewSize = previewSize;

        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera != null) {
            camera.setPreviewSize(previewSize);
            if (camera.isPreviewing()) {
                updateTextureMatrix(surfaceWidth, surfaceHeight, camera.getPreviewSize(), camera.isCameraPortrait());
            }
        }
    }

    public ITPCameraManager.Size getPreviewSize() {
        return previewSize;
    }

    public void setPictureSize(ITPCameraManager.Size pictureSize) {
        this.pictureSize = pictureSize;

        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera != null) {
            camera.setPictureSize(pictureSize);
        }
    }

    public ITPCameraManager.Size getPictureSize() {
        return pictureSize;
    }

    public void setVideoSize(ITPCameraManager.Size videoSize) {
        this.videoSize = videoSize;

        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera != null) {
            camera.setVideoSize(videoSize);
        }
    }

    public ITPCameraManager.Size getVideoSize() {
        return videoSize;
    }

    public void setFocusMode(String focusMode) {
        this.focusMode = focusMode;

        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera != null) {
            try {
                camera.setFocusMode(focusMode);
            } catch (Exception e) {
                Logger.e(TAG, e);
            }
        }
    }

    public String getFocusMode() {
        return focusMode;
    }

    public void setFlashMode(String flashMode) {
        this.flashMode = flashMode;

        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera != null) {
            camera.setFlashMode(flashMode);
        }
    }

    public String getFlashMode() {
        return flashMode;
    }

    public void setRecordingHint(boolean hint) {
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera == null) {
            return;
        }
        camera.setRecordingHint(hint);
    }

    public void toggleCamera() {
        cameraManager.toggleCamera();
        setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera != null && camera.isPreviewing()) {
            updateTextureMatrix(surfaceWidth, surfaceHeight, camera.getPreviewSize(), camera.isCameraPortrait());
        }
    }

    public boolean restoreCameraIfNeed() {
        boolean success = cameraManager.restoreCameraIfNeed();

        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera != null && camera.isPreviewing()) {
            updateTextureMatrix(surfaceWidth, surfaceHeight, camera.getPreviewSize(), camera.isCameraPortrait());
        }

        return success;
    }

    public boolean isFrontCamera() {
        return cameraManager.getCurrentCameraId() == cameraManager.getFrontCameraId();
    }

    public void takePicture(Camera.PictureCallback callback) {
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera == null) {
            return;
        }

        camera.takePicture(callback);
    }

    public void takePictureByPreview(Camera.PictureCallback callback) {
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera == null) {
            Logger.i(TAG, "takePicture camera null");
            return;
        }

        camera.takePictureByPreview(callback);
    }

    public void takePictureByPreviewNoFocus(Camera.PictureCallback callback) {
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera == null) {
            Logger.i(TAG, "takePicture camera null");
            return;
        }

        camera.takePictureByPreviewNoFocus(callback);
    }

    public void takePictureByPreview(boolean focus, Camera.PictureCallback callback) {
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera == null) {
            return;
        }
        Logger.i(TAG, "takePicture takePictureByPreview  start");

        camera.takePictureByPreview(focus, callback);
    }

    public void takePictureByPreviewCompatRealme10(boolean focus, Camera.PictureCallback callback) {
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera == null) {
            return;
        }
        Logger.i(TAG, "takePicture takePictureByPreview  start");

        camera.takePictureByPreviewCompatRealme10(focus, callback);
    }

    public boolean startRecordVideo(File file, MediaRecorder.OnErrorListener errorListener) {
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        return camera != null && camera.startRecordVideo(file, errorListener);
    }

    public void stopRecordVideo() {
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        if (camera == null) {
            return;
        }

        camera.stopRecordVideo();
    }

    public boolean isRecording() {
        ITPCameraManager.CameraWrap camera = cameraManager.getCurrentCamera();
        return camera != null && camera.isRecording();
    }

    public ITPCameraManager getCameraManager() {
        return cameraManager;
    }


    public int getCameraOrientationSensor() {
        try {
            return cameraManager.getCurrentCamera().getCameraOrientationSensor();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}

业务代码

布局文件1

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    android:orientation="vertical"
    android:paddingTop="22dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:gravity="center_vertical"
        android:paddingLeft="10dp"
        app:layout_constraintBottom_toTopOf="@+id/guideline3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/iv_icon"
            android:layout_width="20dp"
            android:layout_height="30dp"
            android:layout_alignParentLeft="true"
            android:src="@drawable/icon_itp_left" />
    </RelativeLayout>

    <com.xxx.xxx.view.ITPCameraView
        android:id="@+id/cameraView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/guideline6"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline3" />

    <include
        android:id="@+id/layout_record_top_bar"
        layout="@layout/item_record_top"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginLeft="11dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline3" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/record_recycler"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="15dp"
        android:background="@color/black"
        app:layout_constraintBottom_toTopOf="@+id/guideline5"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline4" />


    <include
        android:id="@+id/layout_record_bottom_takephoto"
        layout="@layout/item_record_bottom_takephoto"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/black"
        app:layout_constraintBottom_toTopOf="@+id/guideline6"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/record_recycler" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.05" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.7" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.85" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="1" />
</androidx.constraintlayout.widget.ConstraintLayout>

布局文件2

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/record_top_bar"
    android:layout_width="match_parent"
    android:layout_height="42dp"
    android:layout_alignParentTop="true"
    android:layout_marginLeft="15dp"
    android:layout_marginTop="15dp"
    android:layout_marginRight="20dp"
    android:background="@color/transparent">


    <ImageView
        android:id="@+id/flash_current"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_centerVertical="true"
        android:layout_marginRight="28dp"
        android:background="@color/transparent"
        android:src="@drawable/flash_auto" />

    <RelativeLayout
        android:id="@+id/flash_menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_toRightOf="@id/flash_current"
        android:background="@color/transparent"
        android:scaleX="0">

        <TextView
            android:id="@+id/flash_auto"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:background="@color/transparent"
            android:shadowColor="#66000000"
            android:shadowRadius="5"
            android:text="@string/itp_auto"
            android:textColor="#FFFFFFFF"
            android:textSize="13sp" />

        <TextView
            android:id="@+id/flash_on"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="28dp"
            android:layout_toRightOf="@id/flash_auto"
            android:background="@color/transparent"
            android:shadowColor="#66000000"
            android:shadowRadius="5"
            android:text="@string/itp_open"
            android:textColor="#FFFFFFFF"
            android:textSize="13sp" />

        <TextView
            android:id="@+id/flash_off"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="28dp"
            android:layout_toRightOf="@id/flash_on"
            android:background="@color/transparent"
            android:shadowColor="#66000000"
            android:shadowRadius="5"
            android:text="@string/itp_close"
            android:textColor="#FFFFFFFF"
            android:textSize="13sp" />
    </RelativeLayout>

</RelativeLayout>

布局文件3

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

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.xxx.xxx.view.ITPCircleButton
            android:id="@+id/record_bottom_bar_takephoto"
            android:layout_width="45dp"
            android:layout_height="45dp"
            android:layout_centerInParent="true" />
    </RelativeLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ProgressBar
            android:id="@+id/record_bottom_bar_progress"
            style="@style/Widget.AppCompat.ProgressBar.Horizontal"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_centerInParent="true"
            android:indeterminate="false"
            android:indeterminateBehavior="repeat"
            android:indeterminateDrawable="@drawable/progress_bar_shape"
            android:indeterminateDuration="3000"
            android:max="100"
            android:min="0"
            android:progress="100"
            android:progressDrawable="@drawable/progress_bar_green" />

    </RelativeLayout>

</FrameLayout>

业务代码

ITPCameraFragment

public class ITPCameraFragment extends BaseFragment implements View.OnClickListener, ITPPreviewAdapter.OnItemClick {

    public static final String TAG = "ITPCameraFragment";
    private ITPCameraView cameraView;
    private ImageView flashModeBtn;

    private View flashModeMenu, flashAutoBtn, flashOnBtn, flashOffBtn;
    private boolean isFlashModeMenuOpened = false;

    //强制闪光灯,单独逻辑
    private boolean forceFlashOn = false;
    private File currentPictureFile;
    private static AtomicBoolean isTakeFinish;

    //对外监听
    private ITPCameraListener itpCameraListener;
    private ITPPDFPresenter presenter;

    //new
    private FrameLayout record_bottom_bar;
    private ITPCircleButton record_bottom_bar_takephoto;
    private ProgressBar record_bottom_bar_progress;
    private RecyclerView record_recycler;
    private View layout_record_bottom_takephoto;
    private ITPPreviewAdapter adapterPreview;

    private boolean preview_join;
    private int preview_position;
    private ImageData preview_imagedata;

    private enum RecordingMode {
        MODE_RECORDING,
        MODE_RECORDED
    }

    private RecordingMode recordingMode = RecordingMode.MODE_RECORDING;
    private boolean requestingPermission = true;

    public void initPresenter(ITPPDFPresenter itppdfPresenter) {
        this.presenter = itppdfPresenter;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        isTakeFinish = new AtomicBoolean(false);
        return inflater.inflate(R.layout.fragment_itpcamera_new, null);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        checkCameraPermission();
        initTitleBar(view);
        initCameraView(view);
        initView(view);
        S.Interface(IWatchKeyManager.class).registerWatchKeyNeedUnregister(XY_RELEASE_CAMERA_FINISHED, listener);
    }

    private void initTitleBar(View view) {
//        titleBar = view.findViewById(R.id.titleBar);
//        titleBar.setBackgroundColor(getResources().getColor(R.color.black));
    }

    private final IKeyChangeListener<Boolean> listener = new IKeyChangeListener<Boolean>() {
        @Override
        public void onKeyValueChange(String sKey, Boolean value) {
            if (XY_RELEASE_CAMERA_FINISHED.equals(sKey) && value) {
                ThreadUtil.postOnMainThreadDelayed(() -> {
                    if (cameraView == null) {
                        return;
                    }
                    Logger.i(TAG, "onKeyValueChange : " + value);
                    cameraView.startPreview();
                }, 500);
            }
        }
    };

    private void checkCameraPermission() {
        String[] permissions = new String[]{Manifest.permission.CAMERA};
        if (PermissionsUtil.checkSelfPermission(getActivity(), permissions).size() > 0) {
            requestingPermission = true;
            PermissionTextModel textModel = new PermissionTextModel();
            textModel.setForwardToSettingText(BContext.getString(R.string.permission_denied_enable_camera));
            newAcquirePermission(permissions, textModel, grantResultMap -> {
                List<String> successPermissionList = PermissionsUtil.filterSuccessPermission(grantResultMap);
                if (successPermissionList.size() == permissions.length) {
                    // 从后台恢复时需要重新设置摄像机参数
                    boolean isRestore = cameraView.restoreCameraIfNeed();
                    switchToPhotoMode();
                    cameraView.setRecordingHint(true);
                    if (!isRestore && !cameraView.startPreview(false) && !cameraView.startPreview()) {
                        new LXAlertDialog.Builder(cameraView.getContext())
                                .setMessage(getString(R.string.start_camera_failed))
                                .setPositiveButton(getString(R.string.quit), (dlg, which) -> finish())
                                .show();
                    }
                }
            });
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        // 从后台恢复时需要重新设置摄像机参数
        boolean isRestore = cameraView.restoreCameraIfNeed();
        switchToPhotoMode();
        if (!isRestore && !cameraView.startPreview(false) && !requestingPermission) {
            new LXAlertDialog.Builder(cameraView.getContext())
                    .setMessage(getString(R.string.start_camera_failed))
                    .setPositiveButton(getString(R.string.quit), (dlg, which) -> finish())
                    .show();
        }

        S.Interface(IWatchKeyManager.class).notifyKeyChange(XY_RELEASE_CAMERA, true);
    }


    private void initView(View view) {
        //拍摄
        record_bottom_bar = view.findViewById(R.id.record_bottom_bar);
        record_bottom_bar_takephoto = view.findViewById(R.id.record_bottom_bar_takephoto);
        record_bottom_bar_progress = view.findViewById(R.id.record_bottom_bar_progress);
        record_bottom_bar_takephoto.setOnClickListener(this);
        view.findViewById(R.id.iv_icon).setOnClickListener((v) -> {
            if (itpCameraListener != null) {
                itpCameraListener.onCameraCancel();
            }
        });

        //预览图
        layout_record_bottom_takephoto = view.findViewById(R.id.layout_record_bottom_takephoto);
        record_recycler = view.findViewById(R.id.record_recycler);
        adapterPreview = new ITPPreviewAdapter(getActivity());
//        record_recycler.setItemAnimator(null);
        record_recycler.setAdapter(adapterPreview);
        record_recycler.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false));
        adapterPreview.setOnItemClick(this);

        //闪光灯逻辑
        flashModeMenu = view.findViewById(R.id.flash_menu);
        flashModeMenu.setPivotX(0);
        flashModeBtn = view.findViewById(R.id.flash_current);
        flashModeBtn.setOnClickListener(this);
        flashAutoBtn = view.findViewById(R.id.flash_auto);
        flashAutoBtn.setOnClickListener(this);
        flashOnBtn = view.findViewById(R.id.flash_on);
        flashOnBtn.setOnClickListener(this);
        flashOffBtn = view.findViewById(R.id.flash_off);
        flashOffBtn.setOnClickListener(this);
    }

    /**
     * 初始化相机
     */
    private void initCameraView(View view) {
        cameraView = view.findViewById(R.id.cameraView);
        cameraView.init(true);
        //闪光灯
        cameraView.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
        //屏幕的长宽比,读取手机的(自定义mode)
        cameraView.setAspectRatio(ITPCameraManager.AspectRatio.ASPECT_RATIO_AS_SCREEN);
        cameraView.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        cameraView.setRecordingHint(true);
        cameraView.startPreview();
        cameraView.setOnClickListener(v -> {
            if (recordingMode == RecordingMode.MODE_RECORDING) {
                try {
                    //点击屏幕自动对焦
                    Camera camera = cameraView.getCameraManager().getCurrentCamera().getRawCamera();
                    if (camera != null) {
                        Camera.Parameters parameters = camera.getParameters();
                        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                        camera.setParameters(parameters);


                        camera.autoFocus(new Camera.AutoFocusCallback() {
                            @Override
                            public void onAutoFocus(boolean success, Camera camera) {

                            }
                        });

                        //                    camera.stopPreview();
                        camera.startPreview();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            closeFlashModeMenu();
        });
    }

    @Override
    public void onClick(View v) {
        int vId = v.getId();
        if (vId == R.id.record_bottom_bar_takephoto) {
            if (isTakeFinish.get()) {
                return;
            }

            if (!preview_join) {
                boolean b = presenter.checkBitMapMax();
                if (b) {
                    ToastUtil.toast("最多可连拍9张照片");
                    return;
                }
            }

            isTakeFinish.set(true);
            //拍照
            record_bottom_bar_takephoto.setReset(isTakeFinish.get());
            record_bottom_bar_progress.setIndeterminate(isTakeFinish.get());

            //强制闪光灯模拟
            if (forceFlashOn) {
                setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                ThreadUtil.postOnMainThreadDelayed(() -> {
                    if ("RMX3687".equals(Build.MODEL)) {
                        cameraView.takePictureByPreviewCompatRealme10(false, (bytes, camera) -> {
                            processPictureAfter(bytes, camera, forceFlashOn);
                        });
                    } else {
                        //兼容部分手机,开灯之后 没办法聚焦,导致失败
                        cameraView.takePictureByPreviewNoFocus((bytes, camera) -> {
                            processPictureAfter(bytes, camera, forceFlashOn);
                        });
                    }
                }, 800);
                return;
            }

            if ("RMX3687".equals(Build.MODEL)) {
                cameraView.takePictureByPreviewCompatRealme10(false, (bytes, camera) -> {
                    processPictureAfter(bytes, camera, forceFlashOn);
                });
            } else {
                cameraView.takePictureByPreview((bytes, camera) -> {
                    processPictureAfter(bytes, camera, forceFlashOn);
                });
            }

        } else if (vId == R.id.cancel_btn) {
            //取消
            if (itpCameraListener != null) {
                itpCameraListener.onCameraCancel();
            }
        } else if (vId == R.id.return_to_recording_btn) {
            //重拍
            if (itpCameraListener != null) {
                itpCameraListener.onCameraRetakePhoto();
            }
            recordingMode = RecordingMode.MODE_RECORDING;
            cameraView.startPreview();
            updateUIStatus();
        } else if (vId == R.id.sacn_btn) {
            //继续扫描
            if (itpCameraListener != null) {
                itpCameraListener.onCameraFinishPhoto();
            }
            recordingMode = RecordingMode.MODE_RECORDING;
            cameraView.startPreview();
            updateUIStatus();
        } else if (vId == R.id.flash_current) {
            //闪光灯菜单
            if (isFlashModeMenuOpened) {
                ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(flashModeMenu, "scaleX", 1f, 0f);
                ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(flashModeMenu, "alpha", 1f, 0f);
                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.playTogether(scaleAnimator, alphaAnimator);
                animatorSet.setDuration(200);
                animatorSet.setInterpolator(new DecelerateInterpolator());
                animatorSet.start();
            } else {
                ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(flashModeMenu, "scaleX", 0f, 1f);
                ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(flashModeMenu, "alpha", 0f, 1f);
                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.playTogether(scaleAnimator, alphaAnimator);
                animatorSet.setDuration(200);
                animatorSet.setInterpolator(new AccelerateInterpolator());
                animatorSet.start();
            }
            isFlashModeMenuOpened = !isFlashModeMenuOpened;
        } else if (vId == R.id.flash_auto) {
            forceFlashOn = false;
            setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
        } else if (vId == R.id.flash_on) {
            forceFlashOn = true;
            closeFlashModeMenu();
        } else if (vId == R.id.flash_off) {
            forceFlashOn = false;
            setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
        } else if (vId == R.id.insert_btn) {
            //裁剪
            if (itpCameraListener != null) {
                itpCameraListener.onCameraCropping();
            }
        } else if (vId == R.id.recording_pdf) {
            //合成
            itpCameraListener.onCameraSynthesisPdf();
        }
    }

    private void processPictureAfter(byte[] bytes, Camera camera, boolean forceFlashOn) {
        Logger.i(TAG, "processPictureAfter start");
        Observable.just(bytes)
                .flatMap(new Function<byte[], ObservableSource<File>>() {
                    @Override
                    public ObservableSource<File> apply(byte[] bytes) throws Exception {
                        currentPictureFile = ITPSecretLabel.getInstance().generatePictureGzmmFile(getOid());
                        boolean success = presenter.saveJpeg(bytes, currentPictureFile.getAbsolutePath());
                        Logger.i(TAG, "processPictureAfter step1 saveJpeg[%s]", success);
                        if (success) {
                            return Observable.just(currentPictureFile);
                        }
                        return null;
                    }
                })
                .flatMap(new Function<File, ObservableSource<Bitmap>>() {
                    @Override
                    public ObservableSource<Bitmap> apply(File file) throws Exception {
                        if (file.exists()) {
                            Bitmap bitmap = presenter.convertBitMap(getActivity(), file, record_recycler, layout_record_bottom_takephoto, cameraView.getCameraOrientationSensor());
                            Logger.i(TAG, "processPictureAfter step2 decodeBitMap[%s]", bitmap != null ? true : false);
                            if (bitmap != null) {
                                return Observable.just(bitmap);
                            }
                        }
                        return null;
                    }
                })
                .flatMap(new Function<Bitmap, ObservableSource<Bitmap>>() {
                    @Override
                    public ObservableSource<Bitmap> apply(Bitmap bitmap) throws Exception {
                        Bitmap show_bitmap = presenter.convertBitMap(currentPictureFile, bitmap);
                        Logger.i(TAG, "processPictureAfter step3 convertBitMap[%s]", show_bitmap != null ? true : false);
                        if (show_bitmap != null) {
                            return Observable.just(show_bitmap);
                        }
                        return null;
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Bitmap>() {
                    @Override
                    public void accept(Bitmap bitmap) throws Exception {
                        Logger.i(TAG, "processPictureAfter step4 takephotoBitMap[%s]", bitmap != null ? true : false);
                        isTakeFinish.set(false);
                        if (forceFlashOn) {
                            cameraView.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                        }

                        //拍照结果处理的两种可能
                        //step1  正常拍照
                        //step2  预览重拍
                        boolean preview = presenter.isPreview();
                        if (preview && preview_imagedata != null) {
                            boolean success = presenter.savePreviewImg(preview_imagedata, currentPictureFile, bitmap);
                            if (success) {
                                updateUIStatus();
                                //回归选中框,需要重新进入
                                previewUnSelectItemChanged();
                                previewResetParams();
                            } else {
                                presenter.saveCurrentTimesImg(currentPictureFile, bitmap);
                                //拍照
                                updateUIStatus();
                            }
                        } else {
                            presenter.saveCurrentTimesImg(currentPictureFile, bitmap);
                            //拍照
                            updateUIStatus();
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Logger.i(TAG, "processPictureAfter error throwable[%s]", throwable.toString());
                        isTakeFinish.set(false);
                        if (forceFlashOn) {
                            cameraView.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                        }

                        updateUIStatus();
                        ToastUtil.toast(R.string.take_picture_failed);
                    }
                });
    }

    private void previewResetParams() {
        preview_position = 0;
        preview_join = false;
        preview_imagedata = null;
    }

    private void switchToPhotoMode() {
        cameraView.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        cameraView.setRecordingHint(true);
//        setFlashMode(photoMode);
        updateUIStatus();
    }

    private void setFlashMode(String flashMode) {
        cameraView.setFlashMode(flashMode);
        updateUIStatus();
        closeFlashModeMenu();
    }

    private void updateUIStatus() {
        //闪光灯图标切换
        String flashMode = cameraView.getFlashMode();
        if (forceFlashOn) {
            flashModeBtn.setImageResource(R.drawable.flash_on);
        } else if (Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)) {
            flashModeBtn.setImageResource(R.drawable.flash_auto);
        } else if (Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)) {
            flashModeBtn.setImageResource(R.drawable.flash_off);
        } else {
            flashModeBtn.setImageResource(R.drawable.flash_auto);
        }

        record_bottom_bar_takephoto.setReset(isTakeFinish.get());
        record_bottom_bar_progress.setIndeterminate(isTakeFinish.get());

        //更新缩略图
        ArrayList<ImageData> bitMapList = presenter.getBitMapList();
        if (bitMapList.size() > 0) {
            adapterPreview.updateAdapter(bitMapList);
        } else {
            adapterPreview.updateAdapter(new ArrayList<>());
        }
    }


    private void closeFlashModeMenu() {
        if (!isFlashModeMenuOpened) {
            return;
        }

        isFlashModeMenuOpened = false;
        ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(flashModeMenu, "scaleX", 1f, 0f);
        ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(flashModeMenu, "alpha", 1f, 0f);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(scaleAnimator, alphaAnimator);
        animatorSet.setDuration(200);
        animatorSet.setInterpolator(new DecelerateInterpolator());
        animatorSet.start();
    }

    public void onCroppingFinish() {
        if (forceFlashOn) {
            setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
        }

        //回归正常拍照
        recordingMode = ITPCameraFragment.RecordingMode.MODE_RECORDING;
        cameraView.startPreview();
        updateUIStatus();
    }

    public void onPreviewResetTakePhoto(boolean preview, int currentPage, ImageData imageData) {
        this.preview_join = preview;
        this.preview_position = currentPage;
        this.preview_imagedata = imageData;
        previewOnSelectItemChanged(currentPage);

        if (forceFlashOn) {
            setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
        }

        //回归正常拍照
        recordingMode = ITPCameraFragment.RecordingMode.MODE_RECORDING;
        cameraView.startPreview();
        updateUIStatus();
    }

    public void setItpCameraListener(ITPCameraListener itpCameraListener) {
        this.itpCameraListener = itpCameraListener;
    }

    @Override
    public void onItemClick(int position) {
//        if (!presenter.getBitMapList().isEmpty()) {
//            for (ImageData imageData : presenter.getBitMapList()) {
//                imageData.setSelect(false);
//            }
//            presenter.getBitMapList().get(position).setSelect(true);
//            adapterPreview.notifyDataSetChanged();
//        }
        if (preview_join) {
            previewResetParams();
            previewUnSelectItemChanged();
        }
        itpCameraListener.onCameraThumbnail(presenter.getBitMapList().get(position), position);
    }

    public void previewOnSelectItemChanged(int position) {
        if (adapterPreview != null) {
            if (!presenter.getBitMapList().isEmpty()) {
                for (ImageData imageData : presenter.getBitMapList()) {
                    imageData.setSelect(false);
                }
                presenter.getBitMapList().get(position).setSelect(true);
                adapterPreview.notifyItemChanged(position);
            }
        }
    }

    public void previewUnSelectItemChanged() {
        if (adapterPreview != null) {
            if (!presenter.getBitMapList().isEmpty()) {
                for (ImageData imageData : presenter.getBitMapList()) {
                    imageData.setSelect(false);
                }
                adapterPreview.notifyDataSetChanged();
            }
        }
    }

    public interface ITPCameraListener {
        void onCameraCropping();

        void onCameraSynthesisPdf();

        void onCameraThumbnail(ImageData imageData, int position);

        void onCameraCancel();

        void onCameraRetakePhoto();

        void onCameraFinishPhoto();
    }
}

ITPPDFPresenter

public class ITPPDFPresenter {

    private static final String TAG = "ITPPDFPresenter";
    //操作的image合集
    private ArrayList<ImageData> bitMapList = new ArrayList<>(10);
    //是否是预览界面 - 默认不是
    private boolean isPreview = false;
    private boolean isPreviewCrop = false;
    //记录预览界面更改图片的id
    private String previewId = "";

    //记录选择的当前bitmap,根据位置同步更新
    private ImageData selectBitmap = null;
    private int selectPostion = 0;
    private String currentTaskId;

    public ImageData getCurrentImageData() {
        if (!bitMapList.isEmpty()) {
            return bitMapList.get(bitMapList.size() - 1);
        }

        return null;
    }

    public void saveSelectImageData(int postion) {
        if (!bitMapList.isEmpty()) {
            selectPostion = postion;
            selectBitmap = bitMapList.get(postion);
        }
    }

    public ImageData getSelectBitmap() {
        return selectBitmap;
    }

    public int getSelectPosition() {
        return selectPostion;
    }

    public ArrayList<ImageData> getBitMapList() {
        return bitMapList;
    }

    public boolean savePreviewImg(ImageData imageData, File currentPictureFile, Bitmap bitmap) {
        currentTaskId = imageData.getId();
        imageData.setFilepath(currentPictureFile.getAbsolutePath());
        imageData.setBitmap(bitmap);
        return true;
    }

    public void saveCurrentTimesImg(File currentPictureFile, Bitmap bitmap) {
        ImageData currentImageData = new ImageData();
        currentTaskId = UUID.randomUUID().toString().replace("-", "");
        currentImageData.setId(currentTaskId);
        currentImageData.setFilepath(currentPictureFile.getAbsolutePath());
        currentImageData.setBitmap(bitmap);
        bitMapList.add(currentImageData);
    }

    public void removeCurrentImageData() {
        if (!bitMapList.isEmpty() && getCurrentImageData() != null) {
            bitMapList.remove(getCurrentImageData());
        }
    }

    public boolean checkBitMapMax() {
        if (!bitMapList.isEmpty() && bitMapList.size() >= 9) {
            return true;
        }
        return false;
    }

    public void setPreview(boolean b) {
        this.isPreview = b;
    }

    public boolean isPreview() {
        return isPreview;
    }

    public void setPreviewId(String imageDataId) {
        this.previewId = imageDataId;
    }

    public String getPreviewId() {
        return previewId;
    }

    public void setPreviewCrop(boolean b) {
        this.isPreviewCrop = b;
    }

    public boolean isPreviewCrop() {
        return isPreviewCrop;
    }

    public Bitmap convertBitMap(Context context, File currentPictureFile, View view1, View view2, int orientation) {
        //获取原石的bitmap
        Bitmap bitmap = BitmapUtils.decodeFile(currentPictureFile);

        try {
            //1 屏幕大小
            WindowManager manager = (WindowManager) BContext.context().getSystemService(Context.WINDOW_SERVICE);
            Display display = manager.getDefaultDisplay();
            Bitmap newBitmap = null;
            //2 缩放比例
            if (orientation == 90) {
                //手机正向90
                int image_width = bitmap.getWidth();
                int image_height = bitmap.getHeight();
                int screen_height = display.getHeight();
                int view_height = view1.getHeight() + view2.getHeight();
                float scaleHeight = (float) image_height / screen_height;
                int height = ((int) (view_height * scaleHeight));
                newBitmap = Bitmap.createBitmap(bitmap, 0, 0, image_width, (image_height - height));
            } else if (orientation == 180) {
                //手机正向 向右90
                int image_height = bitmap.getHeight();
                int image_width = bitmap.getWidth();
                int view_width = view1.getHeight() + view2.getHeight();
                int screen_width = display.getHeight();
                float scale = (float) image_width / screen_width;
                int sX = ((int) (view_width * scale));
                image_width = image_width - sX;
                newBitmap = Bitmap.createBitmap(bitmap, sX, 0, image_width, image_height);
            } else if (orientation == 270) {
                //手机正向 向右90 向右90
                int image_width = bitmap.getWidth();
                int image_height = bitmap.getHeight();
                int screen_height = display.getHeight();
                int view_height = view1.getHeight() + view2.getHeight();
                float scaleHeight = (float) image_height / screen_height;
                int sY = ((int) (view_height * scaleHeight));
                image_height = image_height - sY;
                newBitmap = Bitmap.createBitmap(bitmap, 0, sY, image_width, image_height);
            } else {
                //手机正向 向右90 向右90
                int image_height = bitmap.getHeight();
                int image_width = bitmap.getWidth();
                int view_width = view1.getHeight() + view2.getHeight();
                int screen_width = display.getHeight();
                float scale = (float) image_width / screen_width;
                int sX = ((int) (view_width * scale));
                image_width = image_width - sX;
                newBitmap = Bitmap.createBitmap(bitmap, 0, 0, image_width, image_height);
            }

            return newBitmap;
        } catch (Exception e) {
            return bitmap;
        }
    }

    public Bitmap convertBitMap(File currentPictureFile, Bitmap bitmap) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        boolean compress = bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
        if (compress) {
            byte[] bytes = stream.toByteArray();
            boolean b = saveJpeg(bytes, currentPictureFile.getAbsolutePath());
            if (b) {
                return bitmap;
            }
        }
        return null;
    }

    public boolean saveJpeg(byte[] data, String outputPath) {
        if (data == null || data.length == 0 || TextUtils.isEmpty(outputPath)) {
            return false;
        }

        File file = new File(outputPath);
        File tmpFile = new File(outputPath + ".tmp");

        //加密生成的文件源
        OutputStream outputStream = TedFileStreamUtils.newFileOutputStream(tmpFile);
        BufferedOutputStream os = null;
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        int len;
        byte[] buffer = new byte[1024 * 8];
        ByteArrayInputStream is = new ByteArrayInputStream(data);
        try {
            os = new BufferedOutputStream(outputStream);
            while ((len = is.read(buffer)) > 0) {
                os.write(buffer, 0, len);
            }

            if (tmpFile.exists()) {
                return tmpFile.renameTo(file);
            }
        } catch (Exception e) {
            Logger.e(TAG, e);
        } finally {
            IOUtil.close(is);
            IOUtil.close(os);
        }
        return false;
    }
}

ITPPreviewAdapter

public class ITPPreviewAdapter extends RecyclerView.Adapter {

    private List<ImageData> datas = new ArrayList<>();
    private List<ImageData> selectData = new ArrayList<>(1);
    private OnItemClick onItemClick;
    private Context context;


    public ITPPreviewAdapter(Context context) {
        this.context = context;
    }

    public void updateAdapter(List<ImageData> data) {
        this.datas = data;
        notifyDataSetChanged();
    }

    public void setOnItemClick(OnItemClick onItemClick) {
        this.onItemClick = onItemClick;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_itp_preview, parent, false));
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ViewHolder viewHolder = (ViewHolder) holder;
//        String filepath = datas.get(position).getFilepath();
//        Bitmap bitmap = BitmapUtils.decodeFile(filepath);

        Logger.i("itp_preview", "onBindViewHolder onBindViewHolder ");
        RequestOptions options = new RequestOptions()
                .placeholder(R.drawable.error_null)
                .bitmapTransform(new RoundedCorners(dip2px(context, 20)));
        Glide.with(context).load(datas.get(position).getBitmap()).apply(options).into(viewHolder.imageView);
        viewHolder.root.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (onItemClick != null) {
                    onItemClick.onItemClick(position);
                }
            }
        });
        viewHolder.root.setSelected(datas.get(position).isSelect());
    }

    @Override
    public int getItemCount() {
        return datas.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        ImageView imageView;
        RelativeLayout root;

        public ViewHolder(View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.item_av);
            root = itemView.findViewById(R.id.root);
        }
    }

    public interface OnItemClick {
        void onItemClick(int position);
    }
}


//布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/root"
    android:layout_width="75dp"
    android:layout_height="75dp"
    android:layout_margin="10dp"
    android:background="@drawable/bg_itp_preview">

    <ImageView
        android:id="@+id/item_av"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp" />

</RelativeLayout>

其他View

ITPCircleButton

public class ITPCircleButton extends AppCompatButton {

    private GradientDrawable backDrawable;
    private volatile boolean isReset = false;

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

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

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

    private GradientDrawable changeBackColor(boolean isReset) {
        this.isReset = isReset;
        if (isReset) {
            int colorDrawable = getResources().getColor(R.color.gray_80);
            backDrawable.setColor(colorDrawable);
            backDrawable.setCornerRadius(120);
            setBackground(backDrawable);
        } else {
            int colorDrawable = getResources().getColor(R.color.white);
            backDrawable.setColor(colorDrawable);
            backDrawable.setCornerRadius(120);
            setBackground(backDrawable);
        }

        return backDrawable;
    }

    private void init(Context context) {
        backDrawable = new GradientDrawable();
        int colorDrawable = context.getResources().getColor(R.color.white);
        backDrawable.setColor(colorDrawable);
        backDrawable.setCornerRadius(120);
        setBackground(backDrawable);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isReset) {
            return true;
        }

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            setScaleX((float) 0.75);
            setScaleY((float) 0.75);
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            setScaleX(1);
            setScaleY(1);
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    public void setReset(boolean isReset) {
        this.isReset = isReset;
        changeBackColor(isReset);
    }
}

YuvUtils

public static byte[] compressToJpeg(byte[] data, int format, int width, int height, int orientation) {
    if (data == null) {
        Logger.e(TAG, "compress To jpeg data=null");
        return null;
    }
    byte[] normalData = null;
    ByteArrayOutputStream outputSteam = null;
    try {
        int imageWidth = 0;
        int imageHeight = 0;
        if (orientation == 90) {
            normalData = rotateYUV420Degree90(data, width, height);
            imageWidth = height;
            imageHeight = width;
        } else if (orientation == 180) {
            normalData = rotateYUV420Degree180(data, width, height);
            imageWidth = width;
            imageHeight = height;
        } else if (orientation == 270) {
            normalData = rotateYUV420Degree270(data, width, height);
            imageWidth = height;
            imageHeight = width;
        } else {
            normalData = data;
            imageWidth = width;
            imageHeight = height;
        }
        YuvImage image = new YuvImage(normalData, format, imageWidth, imageHeight, null);
        outputSteam = new ByteArrayOutputStream();
        image.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()), 90, outputSteam); // 将NV21格式图片,以质量90压缩成Jpeg,并得到JPEG数据流
        normalData = outputSteam.toByteArray();
    } catch (Exception e) {
        Logger.e(TAG, e);
    } finally {
        IoUtil.closeSilently(outputSteam);
    }
    return normalData;
}