version:6.4.6
fix: update:增加护眼模式,增加静默拍照,增加时间管控和专注模式
This commit is contained in:
@@ -0,0 +1,568 @@
|
||||
package com.aoleyun.sn.utils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.camera2.CameraAccessException;
|
||||
import android.hardware.camera2.CameraCaptureSession;
|
||||
import android.hardware.camera2.CameraCharacteristics;
|
||||
import android.hardware.camera2.CameraDevice;
|
||||
import android.hardware.camera2.CameraManager;
|
||||
import android.hardware.camera2.CaptureRequest;
|
||||
import android.hardware.camera2.TotalCaptureResult;
|
||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
||||
import android.media.Image;
|
||||
import android.media.ImageReader;
|
||||
import android.media.MediaRecorder;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.Size;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @作者 Liushihua
|
||||
* @创建时间 2021-2-3 10:54
|
||||
* @描述
|
||||
*/
|
||||
public class Camera2BackgroundUtil {
|
||||
private static final String TAG = Camera2BackgroundUtil.class.getSimpleName();
|
||||
|
||||
private Context context;
|
||||
private CameraCallBack cameraCallBack;
|
||||
private CameraManager cameraManager;
|
||||
// 默认相机id是0 LENS_FACING_FRONT,LENS_FACING_BACK
|
||||
private int cameraId = CameraCharacteristics.LENS_FACING_FRONT;
|
||||
private CameraDevice mCameraDevice;
|
||||
private String savePath;
|
||||
|
||||
private CaptureRequest.Builder mPreviewRequestBuilder;
|
||||
private CameraCaptureSession mCameraCaptureSession;
|
||||
private CaptureRequest request;
|
||||
private ExecutorService service;
|
||||
private boolean isTakedPicture = false;//是否已经拍照
|
||||
|
||||
private int needSetOrientation = 0;// 设置默认的拍照方向
|
||||
private boolean isInitOk = false;// 是否初始化成功
|
||||
private boolean isSessionClosed = true;// captureSession是否被关闭
|
||||
private boolean isCameraDoing = false;// 是否正在使用相机
|
||||
private final long CAPTURE_DELAY_TIME_LONG = 1200;// 延时拍照——聚焦需要时间
|
||||
|
||||
private final int HANDLER_ERR = 3;// 拍照失败
|
||||
private final int HANDLER_TAKE_PHOTO_SUCCESS = 5;// 拍照成功
|
||||
private List<Integer> enableCameraList;//可用摄像头列表
|
||||
private boolean mFlashSupported = false;//是否支持闪光灯
|
||||
private List<Size> recordSizeList;// 录制尺寸
|
||||
private Size mPreviewOutputSize;// 预览尺寸
|
||||
private List<Size> imgOutputSizes;// 拍照尺寸
|
||||
|
||||
private final int PREVIEW_TYPE_NORMAL = 0;// 默认预览
|
||||
private final int PREVIEW_TYPE_RECORD = 1;// 录屏预览
|
||||
private final int PREVIEW_TYPE_TAKE_PHOTO = 2;// 拍照预览
|
||||
private int previewType = 0;//默认预览
|
||||
|
||||
private boolean mTakePictureFinish = false;
|
||||
|
||||
private long lastSaveFileTime = 0;
|
||||
|
||||
public interface CameraCallBack {
|
||||
void onErr(String msg);
|
||||
|
||||
void onTakePhotoOk(String path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理静态图片的输出
|
||||
*/
|
||||
private ImageReader imageReader;
|
||||
|
||||
private Handler handler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
switch (msg.what) {
|
||||
case HANDLER_ERR:
|
||||
cameraCallBack.onErr("" + msg.obj);
|
||||
isCameraDoing = false;
|
||||
break;
|
||||
case HANDLER_TAKE_PHOTO_SUCCESS:
|
||||
if (!mTakePictureFinish) {
|
||||
cameraCallBack.onTakePhotoOk(savePath);
|
||||
mTakePictureFinish = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 当相机设备的状态发生改变的时候,将会回调。
|
||||
*/
|
||||
protected final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
|
||||
/**
|
||||
* 当相机打开的时候,调用
|
||||
* @param cameraDevice
|
||||
*/
|
||||
@Override
|
||||
public void onOpened(@NonNull CameraDevice cameraDevice) {
|
||||
Log.e(TAG, "onOpened");
|
||||
mCameraDevice = cameraDevice;
|
||||
startPreview();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
|
||||
Log.e(TAG, "onDisconnected");
|
||||
cameraDevice.close();
|
||||
mCameraDevice = null;
|
||||
Message message = new Message();
|
||||
message.what = HANDLER_ERR;
|
||||
message.obj = "后台相机断开连接";
|
||||
handler.sendMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发生异常的时候调用
|
||||
*
|
||||
* 这里释放资源,然后关闭界面
|
||||
* @param cameraDevice
|
||||
* @param error
|
||||
*/
|
||||
@Override
|
||||
public void onError(@NonNull CameraDevice cameraDevice, int error) {
|
||||
Log.e(TAG, "onError 相机设备异常,请重启!");
|
||||
cameraDevice.close();
|
||||
mCameraDevice = null;
|
||||
Message messagef = new Message();
|
||||
messagef.what = HANDLER_ERR;
|
||||
messagef.obj = "相机设备异常,请重启!";
|
||||
handler.sendMessage(messagef);
|
||||
}
|
||||
|
||||
/**
|
||||
*当相机被关闭的时候
|
||||
*/
|
||||
@Override
|
||||
public void onClosed(@NonNull CameraDevice camera) {
|
||||
super.onClosed(camera);
|
||||
Log.e(TAG, "onClosed");
|
||||
mCameraDevice = null;
|
||||
isCameraDoing = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 相机状态回调
|
||||
*/
|
||||
private CameraManager.AvailabilityCallback callback = new CameraManager.AvailabilityCallback() {
|
||||
@Override
|
||||
public void onCameraAvailable(@NonNull String cameraId) {// 相机可用
|
||||
super.onCameraAvailable(cameraId);
|
||||
Log.e(TAG, "相机可用");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraUnavailable(@NonNull String cameraId) {// 相机不可用
|
||||
super.onCameraUnavailable(cameraId);
|
||||
Log.e(TAG, "相机不可用");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param activity
|
||||
* @param cameraCallBack 回调
|
||||
*/
|
||||
public Camera2BackgroundUtil(Context activity, @NonNull CameraCallBack cameraCallBack) {
|
||||
this.context = activity;
|
||||
this.cameraCallBack = cameraCallBack;
|
||||
cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
|
||||
// 对于静态图片,使用可用的最大值来拍摄。
|
||||
if (cameraManager != null) {
|
||||
isInitOk = true;
|
||||
cameraManager.registerAvailabilityCallback(callback, null);
|
||||
getCameraInfo();
|
||||
setupImageReader();
|
||||
service = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupImageReader() {
|
||||
// Size size = getOutputSize(imgOutputSizes);
|
||||
//前三个参数分别是需要的尺寸和格式,最后一个参数代表每次最多获取几帧数据,本例的3代表ImageReader中最多可以获取2帧图像流
|
||||
imageReader = ImageReader.newInstance(1600, 1200, ImageFormat.JPEG, 1);
|
||||
//监听ImageReader的事件,当有图像流数据可用时会回调onImageAvailable方法,它的参数就是预览帧数据,可以对这帧数据进行处理
|
||||
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
|
||||
@Override
|
||||
public void onImageAvailable(ImageReader reader) {
|
||||
Image image = reader.acquireLatestImage();
|
||||
//我们可以将这帧数据转成字节数组,类似于Camera1的PreviewCallback回调的预览帧数据
|
||||
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
|
||||
byte[] data = new byte[buffer.remaining()];
|
||||
buffer.get(data);
|
||||
image.close();
|
||||
saveFile(data, savePath);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开相机
|
||||
*/
|
||||
private void openCamera() {
|
||||
cameraId = getFrontCameraId();
|
||||
Log.e(TAG, "openCamera: getFrontCameraId = " + getFrontCameraId());
|
||||
Log.e(TAG, "openCamera:" + cameraId);
|
||||
isCameraDoing = true;
|
||||
// 设置TextureView的缓冲区大小
|
||||
// 获取Surface显示预览数据
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||
Message message = new Message();
|
||||
message.what = HANDLER_ERR;
|
||||
message.obj = "权限不足";
|
||||
handler.sendMessage(message);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
cameraManager.openCamera(Integer.toString(cameraId), stateCallback, null);
|
||||
Log.e(TAG, "打开相机成功!");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "打开相机失败-Exception:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
Message messagef = new Message();
|
||||
messagef.what = HANDLER_ERR;
|
||||
messagef.obj = "打开相机失败";
|
||||
handler.sendMessage(messagef);
|
||||
}
|
||||
}
|
||||
|
||||
private int getFrontCameraId() {
|
||||
int numberOfCameras = Camera.getNumberOfCameras();
|
||||
for (int i = 0; i < numberOfCameras; i++) {
|
||||
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
|
||||
Camera.getCameraInfo(i, cameraInfo);
|
||||
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始视频录制预览
|
||||
*/
|
||||
private void startPreview() {
|
||||
Log.e(TAG, "startPreview");
|
||||
// CaptureRequest添加imageReaderSurface,不加的话就会导致ImageReader的onImageAvailable()方法不会回调
|
||||
// 创建CaptureSession时加上imageReaderSurface,如下,这样预览数据就会同时输出到previewSurface和imageReaderSurface了
|
||||
try {
|
||||
// 创建CaptureRequestBuilder,TEMPLATE_PREVIEW比表示预览请求
|
||||
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
|
||||
mPreviewRequestBuilder.addTarget(imageReader.getSurface());// 设置Surface作为预览数据的显示界面
|
||||
// 创建相机捕获会话,第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession的状态回调接口,当它创建好后会回调onConfigured方法,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行
|
||||
mCameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), captureSessionStateCallBack, null);
|
||||
} catch (CameraAccessException e) {
|
||||
e.printStackTrace();
|
||||
Message messagef = new Message();
|
||||
messagef.what = HANDLER_ERR;
|
||||
messagef.obj = "捕获帧失败";
|
||||
handler.sendMessage(messagef);
|
||||
Log.e(TAG, "Camera获取成功,创建录制请求或捕获Session失败" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 捕获图片数据
|
||||
*/
|
||||
private CameraCaptureSession.StateCallback captureSessionStateCallBack = new CameraCaptureSession.StateCallback() {
|
||||
@Override
|
||||
public void onConfigured(CameraCaptureSession session) {
|
||||
try {
|
||||
mCameraCaptureSession = session;
|
||||
isSessionClosed = false;
|
||||
request = mPreviewRequestBuilder.build();
|
||||
// 设置反复捕获数据的请求,这样预览界面就会一直有数据显示
|
||||
mCameraCaptureSession.setRepeatingRequest(request, null, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Message messagef = new Message();
|
||||
messagef.what = HANDLER_ERR;
|
||||
messagef.obj = "开启图像预览失败";
|
||||
handler.sendMessage(messagef);
|
||||
}
|
||||
if (!isTakedPicture) {
|
||||
isTakedPicture = true;
|
||||
handler.postDelayed(() -> takePicture(), CAPTURE_DELAY_TIME_LONG);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigureFailed(CameraCaptureSession session) {
|
||||
Log.e(TAG, "onConfigureFailed");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public void startTakePicture(String savePath) {
|
||||
Log.e(TAG, "拍照:" + savePath);
|
||||
this.savePath = savePath;
|
||||
if (isCameraDoing) {
|
||||
Log.e(TAG, "相机使用中...");
|
||||
} else {
|
||||
isTakedPicture = false;
|
||||
openCamera();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拍照
|
||||
*/
|
||||
private void takePicture() {
|
||||
Log.e(TAG, "takePicture");
|
||||
try {
|
||||
if (mCameraDevice == null || mPreviewRequestBuilder == null) return;
|
||||
mPreviewRequestBuilder.addTarget(imageReader.getSurface());
|
||||
//设置拍照方向
|
||||
mPreviewRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, this.needSetOrientation);
|
||||
//这个回调接口用于拍照结束时重启预览,因为拍照会导致预览停止
|
||||
CameraCaptureSession.CaptureCallback mImageSavedCallback = new CameraCaptureSession.CaptureCallback() {
|
||||
@Override
|
||||
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
|
||||
Log.e(TAG, "拍照完成");
|
||||
onStop();
|
||||
}
|
||||
};
|
||||
//开始拍照,然后回调上面的接口重启预览,因为mCaptureBuilder设置ImageReader作为target,所以会自动回调ImageReader的onImageAvailable()方法保存图片
|
||||
mCameraCaptureSession.capture(mPreviewRequestBuilder.build(), mImageSavedCallback, null);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "takePhoto CameraAccessException:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
Message messagef = new Message();
|
||||
messagef.what = HANDLER_ERR;
|
||||
messagef.obj = "拍照失败";
|
||||
handler.sendMessage(messagef);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止预览,释放资源
|
||||
*/
|
||||
public void stopRecord() {
|
||||
Log.e(TAG, "停止预览,释放资源");
|
||||
try {
|
||||
if (mCameraCaptureSession != null && !isSessionClosed) {
|
||||
mCameraCaptureSession.stopRepeating();
|
||||
mCameraCaptureSession.abortCaptures();
|
||||
mCameraCaptureSession.close();
|
||||
isSessionClosed = true;
|
||||
imageReader.close();
|
||||
imageReader = null;
|
||||
}
|
||||
if (mCameraDevice != null)
|
||||
mCameraDevice.close();
|
||||
isCameraDoing = false;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "stopRecord-Exception:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置后,开始预览
|
||||
*/
|
||||
public void reset() {
|
||||
previewType = PREVIEW_TYPE_NORMAL;
|
||||
stopRecord();
|
||||
openCamera();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在 activity,fragment的onStop中调用
|
||||
*/
|
||||
public void onStop() {
|
||||
stopRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销 回调
|
||||
*/
|
||||
public void onDestroy() {
|
||||
this.cameraCallBack = null;
|
||||
if (cameraManager != null)
|
||||
cameraManager.unregisterAvailabilityCallback(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得可用的摄像头
|
||||
*
|
||||
* @return SparseArray of available cameras ids。key为摄像头方位,见CameraCharacteristics#LENS_FACING,value为对应的摄像头id
|
||||
*/
|
||||
public void getCameras() {
|
||||
if (cameraManager == null) return;
|
||||
enableCameraList = new ArrayList<>();
|
||||
try {
|
||||
String[] camerasAvailable = cameraManager.getCameraIdList();
|
||||
CameraCharacteristics cam;
|
||||
Integer characteristic;
|
||||
Log.e(TAG, "-------------------------------------");
|
||||
for (String id : camerasAvailable) {
|
||||
Log.e(TAG, "getCameras:" + id);
|
||||
try {
|
||||
enableCameraList.add(Integer.parseInt(id));
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Log.e(TAG, "-------------------------------------");
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "getCameras CameraAccessException:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输出数据尺寸选择器,在selectCamera之前设置有效
|
||||
* (一般手机支持多种输出尺寸,请用户根据自身需要选择最合适的一种)
|
||||
* 举例:
|
||||
* SizeSelector maxPreview = SizeSelectors.and(SizeSelectors.maxWidth(720), SizeSelectors.maxHeight(480));
|
||||
* SizeSelector minPreview = SizeSelectors.and(SizeSelectors.minWidth(320), SizeSelectors.minHeight(240));
|
||||
* camera.setmOutputSizeSelector(SizeSelectors.or(
|
||||
* SizeSelectors.and(maxPreview, minPreview)//先在最大和最小中寻找
|
||||
* , SizeSelectors.and(maxPreview, SizeSelectors.biggest())//找不到则按不超过最大尺寸的那个选择
|
||||
* ));
|
||||
*/
|
||||
public void getOutputSizeSelector() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取摄像头信息
|
||||
*/
|
||||
public void getCameraInfo() {
|
||||
if (enableCameraList == null) {
|
||||
getCameras();
|
||||
}
|
||||
try {
|
||||
CameraCharacteristics mCameraCharacteristics = cameraManager.getCameraCharacteristics(String.valueOf(cameraId));
|
||||
// 设置是否支持闪光灯
|
||||
Boolean available = mCameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
|
||||
mFlashSupported = available == null ? false : available;
|
||||
StreamConfigurationMap map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
||||
if (map == null) {
|
||||
Log.e(TAG, "Could not get configuration map.");
|
||||
return;
|
||||
}
|
||||
int mSensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);//这个方法来获取CameraSensor的方向。
|
||||
Log.e(TAG, "camera sensor orientation:" + mSensorOrientation + ",display rotation=" + context.getDisplay().getRotation());
|
||||
|
||||
int[] formats = map.getOutputFormats();//获得手机支持的输出格式,其中jpeg是一定会支持的,yuv_420_888是api21才开始支持的
|
||||
for (int format : formats) {
|
||||
Log.e(TAG, "手机格式支持: " + format);
|
||||
}
|
||||
Size[] yuvOutputSizes = map.getOutputSizes(ImageFormat.YUV_420_888);
|
||||
Size[] mediaOutputSizes = map.getOutputSizes(MediaRecorder.class);
|
||||
Size[] previewOutputSizes = map.getOutputSizes(SurfaceTexture.class);
|
||||
Size[] jpegOutputSizes = map.getOutputSizes(ImageFormat.JPEG);
|
||||
|
||||
recordSizeList = new ArrayList<>();
|
||||
imgOutputSizes = new ArrayList<>();
|
||||
|
||||
Log.e(TAG, "---------------------------------------------------");
|
||||
for (Size size : mediaOutputSizes) {
|
||||
recordSizeList.add(new Size(size.getWidth(), size.getHeight()));
|
||||
Log.e(TAG, "mediaOutputSizes: " + size.toString());
|
||||
}
|
||||
for (Size size : jpegOutputSizes) {
|
||||
imgOutputSizes.add(new Size(size.getWidth(), size.getHeight()));
|
||||
Log.e(TAG, "jpegOutputSizes: " + size.toString());
|
||||
}
|
||||
for (Size size : previewOutputSizes) {
|
||||
Log.e(TAG, "previewOutputSizes: " + size.toString());
|
||||
}
|
||||
for (Size size : yuvOutputSizes) {
|
||||
Log.e(TAG, "yuvOutputSizes: " + size.toString());
|
||||
}
|
||||
Log.e(TAG, "---------------------------------------------------");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "selectCamera Exception:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private Size getOutputSize(List<Size> sizes) {
|
||||
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
int screenWidth = dm.widthPixels;
|
||||
int screenHeight = dm.heightPixels;
|
||||
Log.e(TAG, "getOutputSize: screenWidth = " + screenWidth);
|
||||
Log.e(TAG, "getOutputSize: screenHeight = " + screenHeight);
|
||||
List<Size> sorted = sizes.stream().sorted(new Comparator<Size>() {
|
||||
@Override
|
||||
public int compare(Size o1, Size o2) {
|
||||
return Long.compare(o1.getHeight() * o1.getWidth(), o2.getHeight() * o2.getWidth());
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
for (Size size : sorted) {
|
||||
if (size.getWidth() > screenHeight && size.getHeight() > screenWidth) {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
return new Size(1600, 1200);
|
||||
}
|
||||
|
||||
//覆盖性保存
|
||||
private void saveFile(final byte[] data, final String savePath) {
|
||||
if (data == null || data.length == 0) return;
|
||||
if (System.currentTimeMillis() - lastSaveFileTime > 1000)
|
||||
service.execute(() -> {
|
||||
File file = new File(savePath);
|
||||
File parent = file.getParentFile();
|
||||
if (parent != null && !parent.exists()) {
|
||||
parent.mkdirs();
|
||||
}
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
try {
|
||||
file.createNewFile();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write(data);
|
||||
fos.flush();
|
||||
fos.close();
|
||||
lastSaveFileTime = System.currentTimeMillis();
|
||||
Message message = new Message();
|
||||
message.what = HANDLER_TAKE_PHOTO_SUCCESS;
|
||||
message.obj = savePath;
|
||||
handler.sendMessage(message);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "图片保存-IOException:" + e.getMessage());
|
||||
Message messagef = new Message();
|
||||
messagef.what = HANDLER_ERR;
|
||||
messagef.obj = "图片保存失败";
|
||||
handler.sendMessage(messagef);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import androidx.annotation.RequiresApi;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.aoleyun.sn.BuildConfig;
|
||||
import com.aoleyun.sn.bean.AdminAppInfo;
|
||||
import com.aoleyun.sn.bean.AppListInfo;
|
||||
import com.aoleyun.sn.bean.Appground;
|
||||
import com.aoleyun.sn.bean.BaseResponse;
|
||||
@@ -2491,4 +2492,44 @@ public class JGYUtils {
|
||||
}
|
||||
cacheHelper.put(CONNECTED_TIME_KEY, GsonUtils.toJSONString(connectedTime));
|
||||
}
|
||||
|
||||
|
||||
public void installAdminApp(List<AdminAppInfo> adminAppInfos) {
|
||||
for (AdminAppInfo adminAppInfo : adminAppInfos) {
|
||||
String app_name = adminAppInfo.getApp_name();
|
||||
String app_package = adminAppInfo.getApp_package();
|
||||
String app_url = adminAppInfo.getApp_url();
|
||||
String app_md5 = adminAppInfo.getApp_md5();
|
||||
int app_id = adminAppInfo.getId();
|
||||
long app_version_code = adminAppInfo.getApp_version_code();
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("app_name", app_name);
|
||||
jsonObject.addProperty("app_package", app_package);
|
||||
jsonObject.addProperty("app_id", app_id);
|
||||
jsonObject.addProperty("MD5", app_md5);
|
||||
PackageInfo packageInfo = null;
|
||||
try {
|
||||
packageInfo = mContext.getPackageManager().getPackageInfo(app_package, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (packageInfo == null) {
|
||||
Log.e(TAG, "installAdminApp: " + app_package + " 未安装");
|
||||
Utils.ariaDownload(mContext, app_url, jsonObject);
|
||||
} else {
|
||||
long appVersionCode;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
appVersionCode = packageInfo.getLongVersionCode();
|
||||
} else {
|
||||
appVersionCode = packageInfo.versionCode;
|
||||
}
|
||||
if (app_version_code > appVersionCode) {
|
||||
Log.e(TAG, "installAdminApp: " + app_package + " 更新");
|
||||
Utils.ariaDownload(mContext, app_url, jsonObject);
|
||||
} else {
|
||||
Log.e(TAG, "installAdminApp: " + app_package + "已安装最新版");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,13 @@ public class TimeUtils {
|
||||
return zeroTime;
|
||||
}
|
||||
|
||||
public static String getPhotoDate() {
|
||||
long millisecond = System.currentTimeMillis();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
|
||||
Date date = new Date(millisecond);
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static boolean isTodayTime(long timeStamp) {
|
||||
String time = transferLongToDate(timeStamp);
|
||||
|
||||
@@ -1322,15 +1322,22 @@ public class Utils {
|
||||
int screenWidth = (int) (width / density); // 屏幕宽度(dp)
|
||||
int screenHeight = (int) (height / density);// 屏幕高度(dp)
|
||||
|
||||
// Log.e("h_bl", "屏幕宽度(像素):" + width);
|
||||
// Log.e("h_bl", "屏幕高度(像素):" + height);
|
||||
// Log.e("h_bl", "屏幕密度(0.75 / 1.0 / 1.5):" + density);
|
||||
// Log.e("h_bl", "屏幕密度dpi(120 / 160 / 240):" + densityDpi);
|
||||
// Log.e("h_bl", "屏幕宽度(dp):" + screenWidth);
|
||||
// Log.e("h_bl", "屏幕高度(dp):" + screenHeight);
|
||||
Log.e("getAndroiodScreenProperty", "屏幕宽度(像素):" + width);
|
||||
Log.e("getAndroiodScreenProperty", "屏幕高度(像素):" + height);
|
||||
Log.e("getAndroiodScreenProperty", "屏幕密度(0.75 / 1.0 / 1.5):" + density);
|
||||
Log.e("getAndroiodScreenProperty", "屏幕密度dpi(120 / 160 / 240):" + densityDpi);
|
||||
Log.e("getAndroiodScreenProperty", "屏幕宽度(dp):" + screenWidth);
|
||||
Log.e("getAndroiodScreenProperty", "屏幕高度(dp):" + screenHeight);
|
||||
return width + "×" + height;
|
||||
}
|
||||
|
||||
public static int getDensityDpi(Context context) {
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getRealMetrics(dm);
|
||||
return dm.densityDpi;
|
||||
}
|
||||
|
||||
public static String getMacAddress() {
|
||||
List<NetworkInterface> interfaces = null;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user