基于旧版本的Camera功能实现,分为几个部分
- Camera管理类
- 业务代码
实现效果(ps:放最前面,仅后置)
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;
}