oxFaceAndroid
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2587 lines
112 KiB

package com.ouxuan.oxface;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.RectF;
import android.hardware.Camera;
import android.os.Handler;
import android.os.Looper;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.baidu.idl.face.main.finance.activity.BaseActivity;
import com.baidu.idl.face.main.finance.callback.CameraDataCallback;
import com.baidu.idl.face.main.finance.callback.FaceDetectCallBack;
import com.baidu.idl.face.main.finance.camera.AutoTexturePreviewView;
import com.baidu.idl.face.main.finance.camera.CameraPreviewManager;
import com.baidu.idl.face.main.finance.manager.FaceSDKManager;
import com.baidu.idl.face.main.finance.model.LivenessModel;
import com.baidu.idl.face.main.finance.model.SingleBaseConfig;
import com.baidu.idl.face.main.finance.utils.BitmapUtils;
import com.baidu.idl.face.main.finance.utils.FaceOnDrawTexturViewUtil;
import com.baidu.idl.face.main.finance.utils.TestPopWindow;
import com.baidu.idl.main.facesdk.FaceInfo;
import com.baidu.idl.main.facesdk.model.BDFaceImageInstance;
import com.ouxuan.oxface.data.DeviceSelectDataManager;
import com.ouxuan.oxface.orderOX.OrderVerificationResultActivity;
import com.ouxuan.oxface.orderOX.OrderSelectionActivity;
import com.ouxuan.oxface.orderOX.VerificationCodeActivity;
import com.ouxuan.oxface.utils.LogManager;
import com.ouxuan.oxface.network.OrderVerificationManager;
import com.ouxuan.oxface.network.OrderVerificationResultHandler;
import com.ouxuan.oxface.network.LeaveVerificationManager;
import com.ouxuan.oxface.utils.VenueSceneUtils;
import com.ouxuan.oxface.network.NetworkStatusIndicator;
import com.ouxuan.oxface.abgate.GateUnavailableDialog;
import com.ouxuan.oxface.abgate.ABGateManager;
import com.ouxuan.oxface.device.GateABController;
import java.util.List;
/**
* 简化版人脸识别界面 - 只显示视频流
*/
public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickListener {
private static final float MIN_FACE_AREA = 1500; //人脸靠近阈值: 人脸面积在屏幕中的像素乘积
private static final String TAG = "OXFaceOnlineActivity";
private static final int CAMERA_PERMISSION_REQUEST_CODE = 1001;
// 图片越大,性能消耗越大,也可以选择640*480, 1280*720
private static final int PREFER_WIDTH = SingleBaseConfig.getBaseConfig().getRgbAndNirWidth();
private static final int PERFER_HEIGH = SingleBaseConfig.getBaseConfig().getRgbAndNirHeight();
// 新增控制变量
private static int PROCESS_FRAME_INTERVAL = 10; // 降低处理频率,每隔10帧处理一次
private int frameCounter = 0;
private boolean needSendFaceImage = false; // 是否需要将人脸图片转为base64发送
private long lastProcessTime = 0;
private long lastBackgroundProcessTime = 0; // 应用在后台时的最后处理时间
private static long MIN_PROCESS_INTERVAL = 1000; // 增加最小处理间隔至1秒
// 智能调节处理频率的控制变量
private static final int FAST_PROCESS_FRAME_INTERVAL = 3; // 快速处理频率:每3帧处理一次
private static final long FAST_MIN_PROCESS_INTERVAL = 300; // 快速处理间隔:300ms
private static final int SLOW_PROCESS_FRAME_INTERVAL = 30; // 慢速处理频率:每30帧处理一次
private static final long SLOW_MIN_PROCESS_INTERVAL = 3000; // 慢速处理间隔:3000ms
private static final long FACE_DETECTION_TIMEOUT = 5000; // 人脸检测超时时间:5秒
private long lastFaceDetectedTime = 0; // 上次检测到人脸的时间
private boolean isFaceDetected = false; // 当前是否检测到人脸
private int consecutiveNoFaceCount = 0; // 连续未检测到人脸的次数
private static final int CONSECUTIVE_NO_FACE_THRESHOLD = 20; // 连续未检测到人脸的阈值
private Context mContext;
private AutoTexturePreviewView mAutoCameraPreviewView;
private TextureView mDrawDetectFaceView;
private RelativeLayout relativeLayout;
private boolean isNeedCamera = true;
private RectF rectF;
private Paint paint;
private Paint paintBg;
private boolean liveStatus;
private LivenessModel currentLivenessModel;
// 新增的视图元素
private TextView preText;
private ImageView previewView;
private RelativeLayout preViewRelativeLayout;
private TextView deveLop;
private RelativeLayout deveLopRelativeLayout;
private ImageView developView;
private TextView preToastText;
private TextView detectSurfaceText;
private ImageView isCheckImage;
private ImageView mFaceDetectImageView;
private TextView mTvDetect;
private TextView mTvLive;
private TextView mTvLiveScore;
private TextView mTvAllTime;
private RelativeLayout progressLayout;
private RelativeLayout layoutCompareStatus;
private TextView textCompareStatus;
private ImageView progressBarView;
private RelativeLayout payHintRl;
private boolean mIsPayHint = true;
private boolean count = true;
private RelativeLayout financeQualityTestFailed;
private TextView qualityTestTimeTv;
private TextView qualityDetectedTv;
private TextView qualityShelteredPart;
private Button qualityRetestDetectBtn;
private RelativeLayout financeByLivingDetection;
private RelativeLayout financeFailedInVivoTest;
private TextView failedInVivoTestRgb;
private TextView failedInVivoTestNir;
private TextView failedInVivoTestDepth;
private TextView failedInVivoTestTime;
private TextView failedInVivoTestFrames;
private TextView byLivingDetectionRgb;
private TextView byLivingDetectionNir;
private TextView byLivingDetectionDepth;
private TextView byLivingTetectionTime;
private TextView byLivingDetectionFrames;
private ImageView qualityDetectRegImageItem;
private ImageView noDetectRegImageItem;
private ImageView detectRegImageItem;
private TestPopWindow testPopWindow;
private View saveCamera;
private boolean isSaveImage;
private View spot;
private boolean isCheck = false;
private boolean isTime = true;
private long searshTime;
private boolean isCompareCheck = false;
// 底部按钮
private Button btnOpenDoor;
private Button btnMemoryInfo; // 新增的内存信息按钮
// private Button btnScanQR;
// private Button btnSettings;
// 新增的二维码区域控件
private ImageView imgMiniProgramCode;
private ImageView imgScanDoorQRCode;
private Button btnVerificationCode;
private Button btnScannerDoor;
// 新增店铺名称相关变量
private TextView tvStoreName;
private int storeNameClickCount = 0;
private long lastStoreNameClickTime = 0;
private static final int MAX_CLICK_COUNT = 5;
private static final long CLICK_INTERVAL = 1000; // 1秒内点击有效
// 新增订单查验相关变量
private int modeType = 0; // 1验证码验证 2人脸验证 3扫码验证 4扫码器验证
private String verifyCode = ""; // 验证码
private com.ouxuan.oxface.data.LoginDataManager loginDataManager; // 新增LoginDataManager实例
private CameraControlReceiver cameraControlReceiver; // 新增摄像头控制广播接收器实例
// 网络请求管理器
private OrderVerificationManager orderVerificationManager;
private OrderVerificationResultHandler orderVerificationResultHandler;
private LeaveVerificationManager leaveVerificationManager;
// 摄像头暂停管理相关
private Handler cameraTimeoutHandler;
private static final int CAMERA_RESUME_TIMEOUT = 60000; // 30秒超时
private boolean isCameraPausedByDialog = false; // 标记是否由对话框暂停
private int pauseRequestCount = 0; // 暂停请求计数
// 网络状态指示器
private NetworkStatusIndicator networkStatusIndicator;
// AB门禁不可用弹窗
private GateUnavailableDialog gateUnavailableDialog;
private GateABController gateABController;
private ABGateManager abGateManager;
private boolean isGateCheckEnabled = false; // AB门检测是否开启
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_oxface_online);
android.util.Log.d(TAG, "onCreate方法开始执行");
LogManager.logInfo(TAG, "OXFaceOnlineActivity onCreate开始");
mContext = this;
// 初始化LoginDataManager
loginDataManager = com.ouxuan.oxface.data.LoginDataManager.getInstance(this);
// 初始化网络请求管理器
initNetworkManagers();
// 初始化离场校验管理器
initLeaveVerificationManager();
initView();
// 初始化网络状态指示器
initNetworkStatusIndicator();
// 初始化AB门禁管理和不可用弹窗
initGateUnavailableDialog();
// 初始化人脸检测状态
lastFaceDetectedTime = System.currentTimeMillis();
isFaceDetected = false;
consecutiveNoFaceCount = 0;
// 检查并请求相机权限
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.CAMERA},
CAMERA_PERMISSION_REQUEST_CODE);
} else {
LogManager.logInfo(TAG, "相机权限已授予");
}
// 启动内存优化周期性任务
startMemoryOptimizationTask();
// 更新小程序码
android.util.Log.d(TAG, "准备调用updateMiniQrcode方法");
updateMiniQrcode();
android.util.Log.d(TAG, "updateMiniQrcode方法调用完成");
LogManager.logInfo(TAG, "OXFaceOnlineActivity onCreate");
android.util.Log.d(TAG, "onCreate方法执行结束");
}
/**
* 初始化离场校验管理器
*/
private void initLeaveVerificationManager() {
// 初始化离场校验管理器
leaveVerificationManager = new LeaveVerificationManager(this, new LeaveVerificationManager.LeaveVerificationListener() {
@Override
public void onLeaveVerificationStart() {
showLoadingStatus("正在进行离场校验...");
}
@Override
public void onLeaveVerificationSuccess(com.ouxuan.oxface.network.api.PadApiService.CheckLeaveResult result) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText(result != null && result.getMessage() != null ?
result.getMessage() : "离场成功");
// 3秒后隐藏状态提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
}, 3000);
}
// 离场校验成功后开启B门
if (gateABController != null) {
LogManager.logInfo(TAG, "离场校验成功,开启B门");
gateABController.handleFaceRecognitionSuccess(false); // 参数保留兼容性,实际都开B门
}
}
});
}
@Override
public void onLeaveVerificationError(int errorCode, String errorMessage) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText(errorMessage != null ? errorMessage : "离场失败");
// 3秒后隐藏状态提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
}, 3000);
}
}
});
}
@Override
public void onLeaveVerificationComplete() {
// 离场校验完成后恢复摄像头
resumeCamera();
}
@Override
public void showToast(String message) {
OXFaceOnlineActivity.this.showToast(message);
}
});
LogManager.logInfo(TAG, "离场校验管理器初始化完成");
}
/**
* 初始化网络请求管理器
*/
private void initNetworkManagers() {
// 初始化订单验证管理器
orderVerificationManager = new OrderVerificationManager(this, new OrderVerificationManager.OrderVerificationListener() {
@Override
public void showLoadingStatus(String message) {
OXFaceOnlineActivity.this.showLoadingStatus(message);
}
@Override
public void hideLoadingStatus() {
OXFaceOnlineActivity.this.hideLoadingStatus();
}
@Override
public void showToast(String message) {
OXFaceOnlineActivity.this.showToast(message);
}
@Override
public void onVerificationSuccess(com.ouxuan.oxface.network.api.PadApiService.CheckOrderResult data, int verificationType) {
// 订单核销成功后开启B门
if (gateABController != null) {
LogManager.logInfo(TAG, "订单核销成功,开启B门");
gateABController.handleFaceRecognitionSuccess(true); // 参数保留兼容性,实际都开B门
}
// 然后处理原有的页面跳转逻辑
orderVerificationResultHandler.handleVerificationSuccess(data, verificationType);
}
@Override
public void onVerificationSuccessWithFullResponse(com.ouxuan.oxface.network.api.PadApiService.CheckOrderResult data, int verificationType, String fullResponseJson) {
// 当前不使用这个方法,保持兼容性
orderVerificationResultHandler.handleVerificationSuccess(data, verificationType);
}
@Override
public void onVerificationError(int errorCode, String errorMessage, int verificationType) {
orderVerificationResultHandler.handleVerificationError(errorCode, errorMessage, verificationType);
}
@Override
public void onVerificationException(Throwable throwable, int verificationType) {
orderVerificationResultHandler.handleVerificationException(throwable, verificationType);
}
@Override
public void onVerificationComplete() {
// 验证完成后恢复摄像头(无论成功或失败)
// 但只在非人脸验证模式下恢复,人脸验证模式下不需要恢复
// 因为人脸验证模式下没有暂停摄像头
LogManager.logInfo(TAG, "验证完成,检查是否需要恢复摄像头");
}
});
// 初始化订单验证结果处理器
orderVerificationResultHandler = new OrderVerificationResultHandler(this, new OrderVerificationResultHandler.OrderVerificationResultListener() {
@Override
public void showToast(String message) {
OXFaceOnlineActivity.this.showToast(message);
}
@Override
public void navigateToResultPage(Intent intent) {
startActivity(intent);
}
@Override
public void navigateToOrderSelectionPage(String orderData, int verificationType, String faceBase64) {
// 在跳转到订单选择页面时暂停摄像头
pauseCameraWithTimeout();
LogManager.logInfo(TAG, "跳转订单选择页面时暂停摄像头");
// 跳转到订单选择页面
Intent intent = new Intent(OXFaceOnlineActivity.this, OrderSelectionActivity.class);
intent.putExtra(OrderSelectionActivity.EXTRA_ORDER_DATA, orderData);
intent.putExtra(OrderSelectionActivity.EXTRA_VERIFICATION_TYPE, verificationType);
if (faceBase64 != null) {
intent.putExtra(OrderSelectionActivity.EXTRA_FACE_BASE64, faceBase64);
}
startActivityForResult(intent, 1002); // 使用新的requestCode
}
});
}
/**
* View
*/
private void initView() {
LogManager.logInfo(TAG, "初始化界面视图");
android.util.Log.d(TAG, "初始化界面视图开始");
// 获取整个布局
relativeLayout = findViewById(R.id.all_relative);
// 单目摄像头RGB 图像预览
mAutoCameraPreviewView = findViewById(R.id.auto_camera_preview_view);
// 画人脸框
rectF = new RectF();
paint = new Paint();
paintBg = new Paint();
mDrawDetectFaceView = findViewById(R.id.draw_detect_face_view);
mDrawDetectFaceView.setOpaque(false);
mDrawDetectFaceView.setKeepScreenOn(true);
LogManager.logInfo(TAG, "镜像设置getRgbRevert"+SingleBaseConfig.getBaseConfig().getRgbRevert());
//TODO 还需要根据实际情况继续调整摄像头镜像参数
android.util.Log.d( "OXFaceOnlineActivity", ": 666666" + SingleBaseConfig.getBaseConfig().getRgbRevert());
if (SingleBaseConfig.getBaseConfig().getRgbRevert()){
mDrawDetectFaceView.setRotationY(180);
}else{
// mDrawDetectFaceView.setRotationY(0);
}
// 店铺名称显示
tvStoreName = findViewById(R.id.tv_store_name);
if (tvStoreName != null) {
// 设置点击事件监听器
tvStoreName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handleStoreNameClick();
}
});
// 获取并显示店铺名称
loadAndDisplayStoreName();
}
// 返回按钮(隐藏但仍保留引用)
ImageView mButReturn = findViewById(R.id.btn_back);
if (mButReturn != null) {
mButReturn.setOnClickListener(this);
}
// 初始化二维码区域控件
imgMiniProgramCode = findViewById(R.id.img_mini_program_code);
imgScanDoorQRCode = findViewById(R.id.img_scan_door_qrcode);
btnVerificationCode = findViewById(R.id.btn_verification_code);
btnScannerDoor = findViewById(R.id.btn_scanner_door);
// 添加调试日志,检查控件是否正确初始化
android.util.Log.d(TAG, "imgMiniProgramCode初始化: " + (imgMiniProgramCode != null));
android.util.Log.d(TAG, "imgScanDoorQRCode初始化: " + (imgScanDoorQRCode != null));
android.util.Log.d(TAG, "btnVerificationCode初始化: " + (btnVerificationCode != null));
android.util.Log.d(TAG, "btnScannerDoor初始化: " + (btnScannerDoor != null));
// 设置二维码区域控件的点击事件
if (imgMiniProgramCode != null) {
imgMiniProgramCode.setOnClickListener(this);
}
if (imgScanDoorQRCode != null) {
imgScanDoorQRCode.setOnClickListener(this);
}
if (btnVerificationCode != null) {
btnVerificationCode.setOnClickListener(this);
}
if (btnScannerDoor != null) {
btnScannerDoor.setOnClickListener(this);
}
// 底部覆盖层,包含按钮和二维码
RelativeLayout bottomOverlay = findViewById(R.id.bottom_overlay);
if (bottomOverlay != null) {
// 确保底部覆盖层显示
bottomOverlay.setVisibility(View.VISIBLE);
}
// 初始化底部按钮
btnOpenDoor = findViewById(R.id.button_open_door);
btnMemoryInfo = findViewById(R.id.button_memory_info); // 初始化内存信息按钮
// btnScanQR = findViewById(R.id.button_scan_qr);
// btnSettings = findViewById(R.id.button_settings);
if (btnOpenDoor != null) {
btnOpenDoor.setOnClickListener(this);
}
if (btnMemoryInfo != null) { // 设置内存信息按钮点击事件
btnMemoryInfo.setOnClickListener(this);
}
// if (btnScanQR != null) {
// btnScanQR.setOnClickListener(this);
// }
// if (btnSettings != null) {
// btnSettings.setOnClickListener(this);
// }
// 隐藏原有的UI元素
hideOriginalUI();
// 初始化状态信息显示
layoutCompareStatus = findViewById(R.id.layout_compare_status);
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
textCompareStatus = findViewById(R.id.text_compare_status);
// 初始化测试弹窗
initTestPopWindow();
android.util.Log.d(TAG, "初始化界面视图结束");
}
/**
* 隐藏原有的UI元素,保持界面简洁
*/
private void hideOriginalUI() {
// 隐藏进度条
if (progressLayout != null) {
progressLayout.setVisibility(View.GONE);
}
progressBarView = findViewById(R.id.progress_bar_view);
if (progressBarView != null) {
progressBarView.setVisibility(View.GONE);
}
// 隐藏提示区域
if (preViewRelativeLayout != null) {
preViewRelativeLayout.setVisibility(View.GONE);
}
// 隐藏其他不需要的UI元素
if (financeQualityTestFailed != null) {
financeQualityTestFailed.setVisibility(View.GONE);
}
if (financeByLivingDetection != null) {
financeByLivingDetection.setVisibility(View.GONE);
}
if (financeFailedInVivoTest != null) {
financeFailedInVivoTest.setVisibility(View.GONE);
}
if (saveCamera != null) {
saveCamera.setVisibility(View.GONE);
}
if (spot != null) {
spot.setVisibility(View.GONE);
}
}
/**
* 初始化测试弹窗
*/
private void initTestPopWindow() {
testPopWindow = new TestPopWindow(this,
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
testPopWindow.setmOnClickFinance(new TestPopWindow.OnClickFinance() {
@Override
public void rester(boolean isReTest) {
// 重新检测
if (isReTest) {
if (testPopWindow != null) {
testPopWindow.closePopupWindow();
}
if (payHintRl != null) {
payHintRl.setVisibility(View.GONE);
}
count = true;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (count) {
isNeedCamera = true;
}
}
}, 500); // 延迟0.5秒执行
} else {
if (testPopWindow != null) {
testPopWindow.closePopupWindow();
}
finish();
}
}
});
}
/**
* 初始化网络状态指示器
*/
private void initNetworkStatusIndicator() {
try {
networkStatusIndicator = new NetworkStatusIndicator(this, relativeLayout);
// 设置网络恢复监听器
networkStatusIndicator.setNetworkRecoveryListener(new NetworkStatusIndicator.NetworkRecoveryListener() {
@Override
public void onNetworkRecovered() {
LogManager.logInfo(TAG, "接收到网络恢复通知,恢复摄像头预览");
// 网络恢复时恢复摄像头预览
resumeCamera();
}
@Override
public void onNetworkLost() {
LogManager.logWarning(TAG, "接收到网络断开通知");
// 网络断开时可以执行一些操作(可选)
// 例如:清理缓存、停止不必要的网络请求等
}
});
networkStatusIndicator.startMonitoring();
LogManager.logInfo(TAG, "网络状态指示器初始化完成");
} catch (Exception e) {
LogManager.logError(TAG, "网络状态指示器初始化失败", e);
}
}
/**
* 初始化AB门禁管理和不可用弹窗
*/
private void initGateUnavailableDialog() {
try {
LogManager.logInfo(TAG, "开始初始化AB门禁管理和不可用弹窗");
// 初始化AB门禁管理器
abGateManager = ABGateManager.getInstance();
abGateManager.initialize(this);
// 初始化门状态控制器
gateABController = GateABController.getInstance();
gateABController.initialize(this);
// 设置门状态监听器(触发时机1)
gateABController.setGateStateListener(new GateABController.GateUnavailableListener() {
@Override
public void onGateStateChanged(GateABController.GateABState state) {
LogManager.logInfo(TAG, "门状态发生变化: " + state.toString());
}
@Override
public void onGateUnavailable(String reason) {
LogManager.logWarning(TAG, "触发门禁不可用弹窗(触发时机1): " + reason);
// 检查是否应该显示弹窗
boolean shouldShow = gateUnavailableDialog.checkShow(OXFaceOnlineActivity.this, isNetworkAvailable());
if (shouldShow) {
// 获取当前门状态信息
GateABController.GateABState currentState = gateABController.getCurrentGateState();
// 如果已有弹窗存在,更新内容(带门状态信息);如果没有,显示新弹窗
gateUnavailableDialog.updateGateStateError(reason,
currentState.gateAOpen,
currentState.gateBOpen,
currentState.udpConnected);
LogManager.logInfo(TAG, "已更新门禁不可用弹窗内容: " + reason);
} else {
LogManager.logInfo(TAG, "根据业务规则,不显示门禁不可用弹窗");
}
}
@Override
public void onGateAvailable() {
LogManager.logInfo(TAG, "门禁恢复可用,隐藏弹窗并恢复摄像头预览");
// 隐藏门禁不可用弹窗
if (gateUnavailableDialog != null && gateUnavailableDialog.isShowing()) {
gateUnavailableDialog.hide();
}
// 恢复摄像头预览(与弹窗的onDialogHide回调保持一致)
resumeCamera();
}
@Override
public void onGateStatusUpdate(boolean gateAOpen, boolean gateBOpen, boolean udpConnected) {
// 实时更新弹窗中的门状态显示
if (gateUnavailableDialog != null && gateUnavailableDialog.isShowing()) {
LogManager.logInfo(TAG, "更新弹窗中的门状态显示: A门-" +
(gateAOpen ? "开启" : "关闭") + ", B门-" +
(gateBOpen ? "开启" : "关闭") + ", UDP-" +
(udpConnected ? "正常" : "异常"));
// 更新弹窗中的门状态显示(保持原有消息不变)
String currentReason = getCurrentDialogReason();
gateUnavailableDialog.updateGateStateError(currentReason, gateAOpen, gateBOpen, udpConnected);
}
// 特别处理:如果A门和B门都关闭且UDP正常,且有弹窗正在显示,应该关闭弹窗
if (!gateAOpen && !gateBOpen && udpConnected &&
gateUnavailableDialog != null && gateUnavailableDialog.isShowing()) {
LogManager.logInfo(TAG, "A门和B门都关闭且UDP正常,关闭门禁不可用弹窗");
gateUnavailableDialog.hide();
resumeCamera();
}
}
});
// 初始化门禁不可用弹窗
gateUnavailableDialog = new GateUnavailableDialog(this);
// 设置弹窗操作监听器
gateUnavailableDialog.setDialogListener(new GateUnavailableDialog.GateUnavailableDialogListener() {
@Override
public void onDialogShow() {
LogManager.logInfo(TAG, "门禁不可用弹窗显示,暂停摄像头和中断操作");
// 暂停摄像头和中断其他操作
pauseCameraWithTimeout();
}
@Override
public void onDialogHide() {
LogManager.logInfo(TAG, "门禁不可用弹窗隐藏,恢复摄像头和操作");
// 恢复摄像头和操作
resumeCamera();
}
@Override
public void onDialogClosed() {
LogManager.logInfo(TAG, "门禁不可用弹窗关闭,恢复正常门禁监控");
// 人数异常弹窗关闭后,恢复正常的门禁监控状态
try {
// 检查UDP是否正常初始化,如果没有则重新初始化
if (gateABController != null && !gateABController.isUDPInitialized()) {
LogManager.logInfo(TAG, "UDP未初始化,重新初始化UDP门禁控制");
gateABController.reinitializeUDP();
// 稍等片刻后启动轮询,确保初始化完成
new Handler(Looper.getMainLooper()).postDelayed(() -> {
if (gateABController != null) {
gateABController.startUDPPolling();
LogManager.logInfo(TAG, "UDP门禁状态轮询已重新启动");
}
}, 500);
}
if (gateABController != null) {
LogManager.logInfo(TAG, "门禁监控已恢复,当前门状态监听器正常运行");
}
} catch (Exception e) {
LogManager.logError(TAG, "恢复UDP门禁监控失败", e);
}
}
});
// 检查是否开启AB门检测
checkGateCheckEnabled();
LogManager.logInfo(TAG, "AB门禁管理和不可用弹窗初始化完成");
} catch (Exception e) {
LogManager.logError(TAG, "AB门禁管理和不可用弹窗初始化失败", e);
}
}
/**
* 显示新的门禁不可用弹窗
* @param reason 不可用原因
*/
private void showNewGateUnavailableDialog(String reason) {
try {
// 执行checkShow()判断是否显示弹窗
boolean shouldShow = gateUnavailableDialog.checkShow(OXFaceOnlineActivity.this, isNetworkAvailable());
if (shouldShow) {
// 如果已有弹窗存在,更新内容;如果没有,显示新弹窗
gateUnavailableDialog.updateGateStateError(reason);
LogManager.logInfo(TAG, "已更新门禁不可用弹窗内容: " + reason);
} else {
LogManager.logInfo(TAG, "根据业务规则,不显示门禁不可用弹窗");
}
} catch (Exception e) {
LogManager.logError(TAG, "显示门禁不可用弹窗失败", e);
}
}
/**
* 获取当前弹窗的原因消息(用于状态更新时保持原有消息)
* @return 当前弹窗的原因消息
*/
private String getCurrentDialogReason() {
if (gateABController != null) {
GateABController.GateABState currentState = gateABController.getCurrentGateState();
return currentState.getUnavailableReason();
}
return "门禁状态异常"; // 默认消息
}
/**
* 显示新的人数异常弹窗
* @param isLeaveScene 是否为离场场景
* @param peopleNum 门内人数
*/
private void showNewPeopleCountDialog(boolean isLeaveScene, int peopleNum) {
try {
// 执行checkShow()判断是否显示弹窗
boolean shouldShow = gateUnavailableDialog.checkShow(OXFaceOnlineActivity.this, isNetworkAvailable());
if (shouldShow) {
// 如果已有弹窗存在,更新内容;如果没有,显示新弹窗
gateUnavailableDialog.updatePeopleCountError(isLeaveScene, peopleNum);
LogManager.logWarning(TAG, "触发门禁不可用弹窗(触发时机2): 人数异常, 场景=" + (isLeaveScene ? "离场" : "进场") + ", 人数=" + peopleNum);
} else {
LogManager.logInfo(TAG, "根据业务规则,不显示门禁不可用弹窗");
}
} catch (Exception e) {
LogManager.logError(TAG, "显示人数异常弹窗失败", e);
}
}
/**
* 检查是否开启AB门检测
*/
private void checkGateCheckEnabled() {
try {
// 从配置中获取AB门检测是否开启
// 这里可以根据实际业务需要添加配置检查逻辑
// 例如:从 DeviceSelectDataManager 获取相关配置
// 暂时默认开启,后续可以根据实际需要调整
isGateCheckEnabled = true;
LogManager.logInfo(TAG, "AB门检测状态: " + (isGateCheckEnabled ? "已开启" : "已关闭"));
} catch (Exception e) {
LogManager.logError(TAG, "检查AB门检测状态失败", e);
isGateCheckEnabled = false; // 异常时默认关闭
}
}
@Override
protected void onResume() {
super.onResume();
// 启动网络状态监控
if (networkStatusIndicator != null) {
networkStatusIndicator.startMonitoring();
}
// 启动UDP门禁状态轮询
if (gateABController != null && gateABController.isUDPInitialized()) {
gateABController.startUDPPolling();
LogManager.logInfo(TAG, "UDP门禁状态轮询已启动");
}
// 只有在拥有相机权限时才启动预览
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) {
startTestOpenDebugRegisterFunction();
}else{
LogManager.logInfo(TAG, "OXFaceOnlineActivity onResume has not CAMERA permission");
}
LogManager.logInfo(TAG, "OXFaceOnlineActivity onResume");
}
private void startTestOpenDebugRegisterFunction() {
LogManager.logInfo(TAG, "启动摄像头预览");
try {
// 设置摄像头方向
if (SingleBaseConfig.getBaseConfig().getRBGCameraId() != -1){
CameraPreviewManager.getInstance().setCameraFacing(SingleBaseConfig.getBaseConfig().getRBGCameraId());
} else {
CameraPreviewManager.getInstance().setCameraFacing(CameraPreviewManager.CAMERA_FACING_FRONT);
}
CameraPreviewManager.getInstance().startPreview(mContext, mAutoCameraPreviewView,
PREFER_WIDTH, PERFER_HEIGH, new CameraDataCallback() {
@Override
public void onGetCameraData(byte[] data, Camera camera, int width, int height) {
try {
// 摄像头预览数据进行人脸检测
if (isNeedCamera) {
// 增加帧计数器和时间间隔控制
frameCounter++;
long currentTime = System.currentTimeMillis();
// 智能调节处理频率
adjustProcessFrequency(currentTime);
// 只有当满足处理条件时才进行人脸检测
if (frameCounter % PROCESS_FRAME_INTERVAL == 0 &&
(currentTime - lastProcessTime) > MIN_PROCESS_INTERVAL) {
lastProcessTime = currentTime;
// 检查应用是否处于前台
if (!isApplicationInForeground()) {
// 如果应用在后台,减少处理频率,每隔10秒处理一次
if ((currentTime - lastBackgroundProcessTime) < 10000) {
return;
}
lastBackgroundProcessTime = currentTime;
}
FaceSDKManager.getInstance().onDetectCheck(data, null, null,
height, width, 1, new FaceDetectCallBack() {
@Override
public void onFaceDetectCallback(LivenessModel livenessModel) {
try {
// 更新人脸检测状态
updateFaceDetectionStatus(livenessModel);
// 开发模式结果输出
checkOpenDebugResult(livenessModel);
} catch (Exception e) {
LogManager.logError(TAG, "人脸检测回调处理异常", e);
}
}
@Override
public void onTip(int code, String msg) {
try {
if(!msg.equals("未检测到人脸")){
LogManager.logInfo(TAG, "人脸检测提示onTip - 代码: " + code + ", 消息: " + msg);
}
} catch (Exception e) {
LogManager.logError(TAG, "人脸检测提示处理异常", e);
}
}
@Override
public void onFaceDetectDarwCallback(LivenessModel livenessModel) {
try {
// 绘制人脸框
showFrame(livenessModel);
} catch (Exception e) {
LogManager.logError(TAG, "人脸框绘制回调处理异常", e);
}
}
});
} else if (frameCounter % 30 == 0) {
// 对于跳过处理的帧,每30帧清空一次画布,确保无人脸时画面干净
try {
LivenessModel emptyModel = new LivenessModel();
emptyModel.setTrackFaceInfo(null);
showFrame(emptyModel);
} catch (Exception e) {
LogManager.logError(TAG, "清空画布时发生异常", e);
}
}
}else{
android.util.Log.d("OXFace", "isNeedCamera: false");
}
} catch (Exception e) {
LogManager.logError(TAG, "摄像头数据处理异常", e);
}
}
});
} catch (Exception e) {
LogManager.logError(TAG, "启动摄像头预览失败", e);
// 尝试重新初始化摄像头
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (!isFinishing()) {
LogManager.logInfo(TAG, "尝试重新启动摄像头预览");
startTestOpenDebugRegisterFunction();
}
}
}, 5000); // 5秒后重试
}
}
/**
* 智能调节处理频率
* @param currentTime 当前时间
*/
private void adjustProcessFrequency(long currentTime) {
// 如果检测到人脸,加速处理
if (isFaceDetected) {
if (PROCESS_FRAME_INTERVAL != FAST_PROCESS_FRAME_INTERVAL ||
MIN_PROCESS_INTERVAL != FAST_MIN_PROCESS_INTERVAL) {
PROCESS_FRAME_INTERVAL = FAST_PROCESS_FRAME_INTERVAL;
MIN_PROCESS_INTERVAL = FAST_MIN_PROCESS_INTERVAL;
LogManager.logInfo(TAG, "检测到人脸,加速处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
}
// 如果长时间未检测到人脸,降低处理频率以节省资源
else if (currentTime - lastFaceDetectedTime > FACE_DETECTION_TIMEOUT) {
// 检查是否已经处于慢速处理模式
if (PROCESS_FRAME_INTERVAL != SLOW_PROCESS_FRAME_INTERVAL ||
MIN_PROCESS_INTERVAL != SLOW_MIN_PROCESS_INTERVAL) {
PROCESS_FRAME_INTERVAL = SLOW_PROCESS_FRAME_INTERVAL;
MIN_PROCESS_INTERVAL = SLOW_MIN_PROCESS_INTERVAL;
LogManager.logInfo(TAG, "长时间未检测到人脸,降低处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
}
}
/**
* 更新人脸检测状态
* @param livenessModel 活体检测模型
*/
private void updateFaceDetectionStatus(LivenessModel livenessModel) {
long currentTime = System.currentTimeMillis();
// 检查是否检测到人脸
boolean faceDetected = (livenessModel != null &&
livenessModel.getTrackFaceInfo() != null &&
livenessModel.getTrackFaceInfo().length > 0);
if (faceDetected) {
// 检测到人脸
isFaceDetected = true;
lastFaceDetectedTime = currentTime;
consecutiveNoFaceCount = 0; // 重置连续未检测到人脸计数器
LogManager.logDebug(TAG, "检测到人脸");
} else {
// 未检测到人脸
consecutiveNoFaceCount++;
// 如果连续多次未检测到人脸,标记为未检测到人脸状态
if (consecutiveNoFaceCount >= CONSECUTIVE_NO_FACE_THRESHOLD) {
isFaceDetected = false;
LogManager.logDebug(TAG, "连续未检测到人脸,当前计数: " + consecutiveNoFaceCount);
}
}
}
/**
* 绘制人脸框
*/
private void showFrame(final LivenessModel model) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Canvas canvas = mDrawDetectFaceView.lockCanvas();
if (canvas == null) {
return;
}
// 始终清空canvas
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// 如果没有模型数据,直接返回清空的画布
if (model == null) {
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
return;
}
// 获取人脸信息
FaceInfo[] faceInfos = model.getTrackFaceInfo();
// 如果没有检测到人脸,直接返回清空的画布
if (faceInfos == null || faceInfos.length == 0) {
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
return;
}
// 只在检测到人脸时绘制人脸框
for (int i = 0; i < faceInfos.length; i++) {
FaceInfo faceInfo = faceInfos[i];
// 如果人脸置信度太低,不绘制
if (faceInfo.score < 0.6) {
continue;
}
rectF.set(FaceOnDrawTexturViewUtil.getFaceRectTwo(faceInfo));
// 检测图片的坐标和显示的坐标不一样,需要转换。
FaceOnDrawTexturViewUtil.mapFromOriginalRect(rectF,
mAutoCameraPreviewView, model.getBdFaceImageInstance());
// 人脸框颜色
FaceOnDrawTexturViewUtil.drawFaceColor(paint, paintBg, liveStatus, model);
// 绘制人脸框
FaceOnDrawTexturViewUtil.drawRect(canvas,
rectF, paint, 5f, 50f, 25f);
}
// 提交canvas
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
}
});
}
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.btn_back) {
finish();
} else if (id == R.id.button_open_door) {
// 开门按钮点击事件
handleOpenDoorClick();
} else if (id == R.id.button_memory_info) {
// 内存信息按钮点击事件
displayMemoryInfo();
}
// else if (id == R.id.button_scan_qr) {
// // 扫码按钮点击事件
// handleScanQRClick();
// } else if (id == R.id.button_settings) {
// // 设置按钮点击事件
// handleSettingsClick();
// }
else if (id == R.id.img_mini_program_code) {
// 新用户扫码上传人脸点击事件
handleMiniProgramCodeClick();
} else if (id == R.id.img_scan_door_qrcode) {
// 扫码开门点击事件
handleScanDoorQRCodeClick();
} else if (id == R.id.btn_verification_code) {
// 验证码开门点击事件
handleVerificationCodeClick();
} else if (id == R.id.btn_scanner_door) {
// 扫码器开门点击事件
handleScannerDoorClick();
}
}
/**
* 处理开门按钮点击事件
*/
private void handleOpenDoorClick() {
LogManager.logInfo(TAG, "用户点击开门按钮");
Toast.makeText(this, "开门功能已触发", Toast.LENGTH_SHORT).show();
// 这里可以添加实际的开门逻辑
// 例如:发送网络请求到服务器执行开门操作
// 或者通过蓝牙/WiFi连接门锁设备
// 显示开门状态
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText("正在开门...");
// 3秒后隐藏状态提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
}, 3000);
}
}
/**
* 处理扫码按钮点击事件
*/
// private void handleScanQRClick() {
// LogManager.logInfo(TAG, "用户点击扫码按钮");
// Toast.makeText(this, "扫码功能已触发", Toast.LENGTH_SHORT).show();
// // 这里可以添加实际的扫码逻辑
// // 例如:启动扫码Activity或显示扫码界面
// // 显示扫码状态
// if (layoutCompareStatus != null) {
// layoutCompareStatus.setVisibility(View.VISIBLE);
// textCompareStatus.setTextColor(Color.parseColor("#009874"));
// textCompareStatus.setText("请将二维码对准扫描区域");
// // 3秒后隐藏状态提示
// new Handler().postDelayed(new Runnable() {
// @Override
// public void run() {
// if (layoutCompareStatus != null) {
// layoutCompareStatus.setVisibility(View.GONE);
// }
// }
// }, 3000);
// }
// }
/**
* 处理设置按钮点击事件
*/
private void handleSettingsClick() {
LogManager.logInfo(TAG, "用户点击设置按钮");
Toast.makeText(this, "设置功能已触发", Toast.LENGTH_SHORT).show();
// 这里可以添加实际的设置逻辑
// 例如:启动设置Activity或显示设置对话框
// 显示设置状态
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText("正在加载设置...");
// 3秒后隐藏状态提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
}, 3000);
}
}
/**
* 处理新用户扫码上传人脸点击事件
*/
private void handleMiniProgramCodeClick() {
LogManager.logInfo(TAG, "用户点击新用户扫码上传人脸");
Toast.makeText(this, "新用户扫码上传人脸功能已触发", Toast.LENGTH_SHORT).show();
// 这里可以添加实际的扫码逻辑
// 例如:启动扫码Activity或显示扫码界面
// 显示扫码状态
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText("请使用小程序扫码上传人脸");
// 3秒后隐藏状态提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
}, 3000);
}
}
/**
* 处理扫码开门点击事件
*/
private void handleScanDoorQRCodeClick() {
LogManager.logInfo(TAG, "用户点击扫码开门");
Toast.makeText(this, "扫码开门功能已触发", Toast.LENGTH_SHORT).show();
// 这里可以添加实际的扫码开门逻辑
// 例如:启动扫码Activity或显示扫码界面
// 显示扫码状态
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText("请扫描二维码开门");
// 3秒后隐藏状态提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
}, 3000);
}
}
/**
* 处理验证码开门点击事件
*/
private void handleVerificationCodeClick() {
LogManager.logInfo(TAG, "用户点击验证码开门");
// 使用新的暂停摄像头方法
pauseCameraWithTimeout();
LogManager.logInfo(TAG, "暂停摄像头预览 - 使用带超时的暂停方法");
// 启动验证码Activity
Intent intent = new Intent(this, VerificationCodeActivity.class);
startActivityForResult(intent, 1001);
}
/**
* 处理扫码器开门点击事件
*/
private void handleScannerDoorClick2() {
LogManager.logInfo(TAG, "用户点击扫码器开门");
// 检查是否有正在进行的人脸识别请求
if (orderVerificationManager != null && orderVerificationManager.isRequestInProgress()) {
LogManager.logInfo(TAG, "有正在进行的订单验证请求,取消扫码操作");
Toast.makeText(this, "正在处理其他请求,请稍后再试", Toast.LENGTH_SHORT).show();
return;
}
// 暂停摄像头预览
pauseCameraWithTimeout();
LogManager.logInfo(TAG, "已暂停摄像头预览");
// 调用华为统一扫码功能
com.ouxuan.oxface.device.HuaWeiScanManager.doScan(this, new com.ouxuan.oxface.device.HuaWeiScanManager.ScanResultListener() {
@Override
public void onScanSuccess(String scanResult) {
LogManager.logInfo(TAG, "华为扫码器扫码成功,结果: " + scanResult);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OXFaceOnlineActivity.this, "扫码成功: " + scanResult, Toast.LENGTH_SHORT).show();
// 设置模式为4(扫码器验证)
modeType = OrderVerificationManager.TYPE_SCANNER_VERIFICATION;
verifyCode = scanResult;
// 执行扫码器核销
getCheckOrder();
}
});
}
@Override
public void onScanFailed(int errorCode, String errorMsg) {
LogManager.logError(TAG, "华为扫码器扫码失败,错误码: " + errorCode + ", 错误信息: " + errorMsg);
// 恢复摄像头预览
resumeCamera();
LogManager.logInfo(TAG, "扫码失败,已恢复摄像头预览");
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OXFaceOnlineActivity.this, "扫码失败: " + errorMsg, Toast.LENGTH_SHORT).show();
// 显示状态提示
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#FF0000"));
textCompareStatus.setText("扫码失败: " + errorMsg);
// 3秒后隐藏状态提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
}, 3000);
}
}
});
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
LogManager.logInfo(TAG, "相机权限已授予,启动摄像头预览");
startTestOpenDebugRegisterFunction();
} else {
LogManager.logError(TAG, "相机权限被拒绝");
Toast.makeText(this, "需要相机权限才能使用人脸识别功能", Toast.LENGTH_LONG).show();
finish();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 销毁网络状态指示器
if (networkStatusIndicator != null) {
networkStatusIndicator.destroy();
networkStatusIndicator = null;
}
// 释放AB门禁管理和不可用弹窗资源
if (gateUnavailableDialog != null) {
gateUnavailableDialog.release();
gateUnavailableDialog = null;
LogManager.logInfo(TAG, "门禁不可用弹窗资源已释放");
}
if (gateABController != null) {
gateABController.release();
gateABController = null;
LogManager.logInfo(TAG, "AB门控制器资源已释放");
}
if (abGateManager != null) {
abGateManager.release();
abGateManager = null;
LogManager.logInfo(TAG, "AB门禁管理器资源已释放");
}
// 注销广播接收器
if (cameraControlReceiver != null) {
unregisterReceiver(cameraControlReceiver);
LogManager.logInfo(TAG, "摄像头控制广播接收器已注销");
}
// 停止摄像头预览
if (CameraPreviewManager.getInstance() != null) {
CameraPreviewManager.getInstance().stopPreview();
}
// 释放当前的LivenessModel资源
if (currentLivenessModel != null) {
BDFaceImageInstance image = currentLivenessModel.getBdFaceImageInstance();
if (image != null) {
image.destory();
}
// 清空引用
currentLivenessModel = null;
}
// 释放绘图资源
if (rectF != null) {
rectF = null;
}
if (paint != null) {
paint = null;
}
if (paintBg != null) {
paintBg = null;
}
// 清除其他相关资源
System.gc();
LogManager.logInfo(TAG, "OXFaceOnlineActivity onDestroy - 资源已释放");
}
@Override
protected void onStop() {
super.onStop();
// 停止网络状态监控
if (networkStatusIndicator != null) {
networkStatusIndicator.stopMonitoring();
}
// 停止UDP门禁状态轮询
if (gateABController != null) {
gateABController.stopUDPPolling();
LogManager.logInfo(TAG, "UDP门禁状态轮询已停止");
}
LogManager.logInfo(TAG, "OXFaceOnlineActivity onStop - 应用进入后台");
// 应用进入后台时,进一步降低处理频率以节省资源
PROCESS_FRAME_INTERVAL = 30; // 后台时每30帧处理一次
MIN_PROCESS_INTERVAL = 3000; // 后台时最小间隔3秒
LogManager.logInfo(TAG, "后台模式处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
@Override
protected void onStart() {
super.onStart();
LogManager.logInfo(TAG, "OXFaceOnlineActivity onStart - 应用回到前台");
// 应用回到前台时,恢复正常的处理频率
PROCESS_FRAME_INTERVAL = FAST_PROCESS_FRAME_INTERVAL; // 前台时使用快速处理频率
MIN_PROCESS_INTERVAL = FAST_MIN_PROCESS_INTERVAL; // 前台时使用快速处理间隔
LogManager.logInfo(TAG, "前台模式处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
// ***************开发模式结果输出*************
private void checkOpenDebugResult(final LivenessModel livenessModel) {
// 当未检测到人脸UI显示
runOnUiThread(new Runnable() {
@Override
public void run() {
layoutCompareStatus.setBackgroundColor(Color.parseColor("#CC000000"));
if (livenessModel == null) {
liveStatus = false;
layoutCompareStatus.setVisibility(View.GONE);
// mFaceDetectImageView.setImageResource(R.mipmap.ic_image_video);
// mTvDetect.setText(String.format("检测耗时 :%s ms", 0));
// mTvLive.setText(String.format("RGB活体检测耗时 :%s ms", 0));
// mTvLiveScore.setText(String.format("RGB活体检测结果 :%s", false));
// mTvAllTime.setText(String.format("总耗时 :%s ms", 0));
return;
}
BDFaceImageInstance image = livenessModel.getBdFaceImageInstance();
if (image != null) {
// mFaceDetectImageView.setImageBitmap(BitmapUtils.getInstaceBmp(image));
float faceArea = livenessModel.getFaceInfo().width * livenessModel.getFaceInfo().height;
image.destory();
// 新增:人脸过小检测
if (faceArea < MIN_FACE_AREA) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText("请靠近设备");
return;
}
}
// 模糊结果过滤
float blur = livenessModel.getFaceInfo().bluriness;
if (blur > SingleBaseConfig.getBaseConfig().getBlur()) {
//照片模糊
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText("人脸模糊,请摘掉眼镜帽子调整识别角度");
return;
}
//质量检测
if (!livenessModel.isQualityCheck()) {
liveStatus = false;
} else {
// 活体检测逻辑
if (SingleBaseConfig.getBaseConfig().isLivingControl()) {
if (livenessModel.isRGBLiveStatus()) {
liveStatus = true;
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText("通过活体检测");
} else {
liveStatus = false;
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText("请尝试移动人脸到屏幕正中");
return;
}
}
}
FaceInfo faceInfo = livenessModel.getFaceInfo();
if (faceInfo.bestImageScore < SingleBaseConfig.getBaseConfig().getBestImageScore()) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText("阈值低于" + SingleBaseConfig.getBaseConfig().getBestImageScore());
return;
}
//通过检测
if (livenessModel != null) {
checkResultOnline(livenessModel);//在线人脸检测
} else {
currentLivenessModel = null;
}
}
});
}
private void checkResultOnline(LivenessModel livenessModel) {
this.currentLivenessModel = livenessModel;
// 当未检测到人脸UI显示
runOnUiThread(new Runnable() {
@Override
public void run() {
if (livenessModel == null) {
return;
}
// 减少base64转换频率,只有在特定条件下才进行转换
// 例如:每3秒检查一次是否需要发送人脸图像
long currentTime = System.currentTimeMillis();
if (currentTime - searshTime > 3000) {
searshTime = currentTime;
needSendFaceImage = true;
// 触发时机2:在线人脸检测开始前进行AB门人数检测
if (isGateCheckEnabled && abGateManager != null) {
LogManager.logInfo(TAG, "开始执行AB门人数检测(触发时机2)");
// 在后台线程中执行AB门人数检测
new Thread(() -> {
try {
// 执行人数检测
boolean peopleCheckPassed = abGateManager.ABPeopleCheck();
if (!peopleCheckPassed) {
// 人数检测未通过,显示弹窗
runOnUiThread(() -> {
try {
// 判断场景类型
boolean isLeaveScene = VenueSceneUtils.isLeaveScene(OXFaceOnlineActivity.this);
// 获取实际人数用于显示
gateABController.get485PeopleNum(new GateABController.PeopleNumCallback() {
@Override
public void onSuccess(int peopleNum) {
// 直接更新弹窗内容,不需要检查重复弹窗
showNewPeopleCountDialog(isLeaveScene, peopleNum);
}
@Override
public void onError(String errorMessage) {
LogManager.logError(TAG, "获取人数失败,无法显示具体人数: " + errorMessage);
// 直接更新弹窗内容,不需要检查重复弹窗
showNewGateUnavailableDialog("门禁内人数不符合要求,请等待");
}
});
} catch (Exception e) {
LogManager.logError(TAG, "处理人数检测结果异常", e);
}
});
// 人数检测未通过,中断后续的人脸识别流程
LogManager.logInfo(TAG, "AB门人数检测未通过,中断后续人脸识别流程");
return;
} else {
LogManager.logInfo(TAG, "AB门人数检测通过,继续人脸识别流程");
}
} catch (Exception e) {
LogManager.logError(TAG, "AB门人数检测异常", e);
// 异常情况下继续正常流程,不阻塞用户操作
LogManager.logInfo(TAG, "AB门检测异常,继续正常人脸识别流程");
}
// 继续正常的人脸识别流程(只有在检测通过或异常时才执行)
runOnUiThread(() -> processFaceRecognitionFlow());
}).start();
// AB门检测开启时,先返回,等待后台维续
return;
} else {
// AB门检测未开启,直接继续正常流程
processFaceRecognitionFlow();
}
} else {
// 时间间隔不够,跳过本次处理
}
}
});
}
/**
* 处理人脸识别流程(从 checkResultOnline 中抽取出来)
*/
private void processFaceRecognitionFlow() {
String base64img = getFaceImageBase64(currentLivenessModel);
if (base64img != null) {
// 这里可以处理base64数据,如上传到服务器等
Log.i(TAG, "processFaceRecognitionFlow: 获取到人脸base64数据");
// 保存人脸base64数据到verifyCode变量
verifyCode = base64img;
// 设置模式为2(人脸验证)
modeType = OrderVerificationManager.TYPE_FACE_VERIFICATION;
// 判断是进场还是离场场景
if (VenueSceneUtils.isLeaveScene(OXFaceOnlineActivity.this)) {
// 离场场景:检查gate_enter_open_enable配置
VenueSceneUtils.GateConfig gateConfig = VenueSceneUtils.getGateConfig(OXFaceOnlineActivity.this);
if (gateConfig != null && gateConfig.gateEnterOpenEnable) {
// 如果 gate_enter_open_enable 为 true,直接开门不进行网络核销
LogManager.logInfo(TAG, "检测到离场场景,gate_enter_open_enable为true,直接开启B门");
showLoadingStatus("离场验证成功");
// 2秒后隐藏提示并开门
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
hideLoadingStatus();
// 直接开启B门
if (gateABController != null) {
LogManager.logInfo(TAG, "gate_enter_open_enable为true,直接开启B门");
gateABController.handleFaceRecognitionSuccess(false); // 参数保留兼容性,实际都开B门
}
}
}, 2000);
} else {
// gate_enter_open_enable 为 false 或配置不存在,按正常流程进行网络校验
if (isNetworkAvailable()) {
LogManager.logInfo(TAG, "检测到离场场景,网络可用,执行离场校验");
performLeaveVerification(base64img);
} else {
LogManager.logWarning(TAG, "检测到离场场景,但网络不可用,直接开启B门");
showLoadingStatus("网络不可用,直接开门");
// 直接开启B门,防止用户卡在场内
if (gateABController != null) {
LogManager.logInfo(TAG, "离场场景网络不可用,直接开启B门");
gateABController.handleFaceRecognitionSuccess(false); // 开启B门
}
// 3秒后隐藏提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
hideLoadingStatus();
}
}, 3000);
}
}
} else {
// 进场场景:先检查网络状态
if (isNetworkAvailable()) {
LogManager.logInfo(TAG, "检测到进场场景,网络可用,执行订单核销");
// 检查是否已有正在进行的人脸验证请求,避免重复请求
if (orderVerificationManager != null && orderVerificationManager.isRequestInProgress()) {
LogManager.logInfo(TAG, "已有正在进行的人脸验证请求,跳过本次请求");
return;
}
getCheckOrder();
} else {
LogManager.logWarning(TAG, "检测到进场场景,但网络不可用");
showLoadingStatus("无网络连接,请检查网络设置");
// 3秒后隐藏提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
hideLoadingStatus();
}
}, 3000);
// 网络不可用时,不执行任何门禁操作,保持安全
LogManager.logInfo(TAG, "进场场景网络不可用,等待网络恢复");
}
}
// 处理完成后重置标志
needSendFaceImage = false;
} else {
Log.i(TAG, "processFaceRecognitionFlow: base64img score too low ");
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText("请重新识别");
}
}
private String getFaceImageBase64(LivenessModel livenessModel) {
if (livenessModel == null) return null;
FaceInfo faceInfo = livenessModel.getFaceInfo();
// 添加判断条件,减少不必要的base64转换
Log.d(TAG, faceInfo.leftEyeclose+" "+faceInfo.score+" getFaceImageBase64: "+faceInfo.bestImageScore + " getBestImageScore-Config:"+SingleBaseConfig.getBaseConfig().getBestImageScore());
if (faceInfo != null && faceInfo.bestImageScore > SingleBaseConfig.getBaseConfig().getBestImageScore()) {
BDFaceImageInstance image = livenessModel.getBdFaceImageInstance();
if (image != null) {
Bitmap bitmap = BitmapUtils.getInstaceBmp(image);
// 仅在确实需要使用base64数据时才进行转换
if (needSendFaceImage) {
String bitmap_str = BitmapUtils.bitmapToBase64(bitmap);
image.destory();
return bitmap_str;
} else {
// 如果不需要发送,则不进行base64转换,直接释放资源
image.destory();
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
return "dummy_base64_placeholder";
}
}
}
return null;
}
/**
* 检查应用是否在前台
* @return 如果应用在前台,则返回true;否则返回false
*/
private boolean isApplicationInForeground() {
android.app.ActivityManager activityManager = (android.app.ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<android.app.ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
String packageName = getPackageName();
for (android.app.ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
&& appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
/**
* 低内存时的处理
*/
@Override
public void onLowMemory() {
super.onLowMemory();
LogManager.logInfo(TAG, "系统内存不足,触发onLowMemory");
// 清理不必要的缓存
clearMemoryCache();
// 强制GC
System.gc();
}
/**
* 清理内存缓存
*/
private void clearMemoryCache() {
// 如果当前不在人脸检测状态,释放当前的LivenessModel
if (currentLivenessModel != null && !isNeedCamera) {
BDFaceImageInstance image = currentLivenessModel.getBdFaceImageInstance();
if (image != null) {
image.destory();
}
currentLivenessModel = null;
}
// 如果设备内存不足,考虑调整处理频率
PROCESS_FRAME_INTERVAL = Math.min(30, PROCESS_FRAME_INTERVAL + 5);
MIN_PROCESS_INTERVAL = Math.min(3000, MIN_PROCESS_INTERVAL + 500);
LogManager.logInfo(TAG, "内存不足,调整处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
}
/**
* 优化内存的周期性任务
*/
private void startMemoryOptimizationTask() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// 获取当前应用内存使用情况
Runtime runtime = Runtime.getRuntime();
long usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024);
long totalMemory = runtime.maxMemory() / (1024 * 1024);
float memoryUsageRatio = (float) usedMemory / totalMemory;
LogManager.logInfo(TAG, "内存使用情况:" + usedMemory + "MB/" + totalMemory +
"MB,使用率:" + (int)(memoryUsageRatio * 100) + "%");
// 如果内存使用率超过70%,主动清理内存
if (memoryUsageRatio > 0.7f) {
LogManager.logInfo(TAG, "内存使用率超过70%,主动清理内存");
clearMemoryCache();
System.gc();
}
// 如果内存使用率超过85%,进行更积极的清理
if (memoryUsageRatio > 0.85f) {
LogManager.logWarning(TAG, "内存使用率超过85%,进行积极清理");
// 进一步降低处理频率
PROCESS_FRAME_INTERVAL = Math.min(50, PROCESS_FRAME_INTERVAL + 10);
MIN_PROCESS_INTERVAL = Math.min(5000, MIN_PROCESS_INTERVAL + 1000);
// 清理更多资源
if (currentLivenessModel != null) {
BDFaceImageInstance image = currentLivenessModel.getBdFaceImageInstance();
if (image != null) {
image.destory();
}
currentLivenessModel = null;
}
LogManager.logInfo(TAG, "积极清理后调整处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
System.gc();
}
// 每30秒执行一次
if (!isFinishing()) {
new Handler().postDelayed(this, 30000);
}
}
}, 30000);
}
/**
* 更新小程序码显示
*/
private void updateMiniQrcode() {
LogManager.logInfo(TAG, "开始更新小程序码");
try {
DeviceSelectDataManager deviceSelectDataManager = DeviceSelectDataManager.getInstance(this);
// 更新普通小程序码(扫码开门)
boolean hasQrcode = deviceSelectDataManager.hasMiniQrcodeUrl();
if (hasQrcode) {
String base64Qrcode = deviceSelectDataManager.getMiniQrcodeUrl();
if (base64Qrcode != null && !base64Qrcode.isEmpty()) {
// 在主线程中更新UI
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
// 处理base64数据并显示二维码
String decodedBase64 = base64Qrcode;
if (base64Qrcode.startsWith("data:image")) {
int commaIndex = base64Qrcode.indexOf(',');
if (commaIndex > 0) {
decodedBase64 = base64Qrcode.substring(commaIndex + 1);
}
}
Bitmap qrcodeBitmap = BitmapUtils.base64ToBitmap(decodedBase64);
if (qrcodeBitmap != null && imgScanDoorQRCode != null) {
imgScanDoorQRCode.setImageBitmap(qrcodeBitmap);
LogManager.logInfo(TAG, "扫码开门小程序码更新成功");
} else {
LogManager.logWarning(TAG, "扫码开门小程序码更新失败");
}
} catch (Exception e) {
LogManager.logError(TAG, "更新扫码开门小程序码异常: " + e.getMessage(), e);
}
}
});
} else {
LogManager.logWarning(TAG, "扫码开门小程序码数据为空");
}
} else {
LogManager.logDebug(TAG, "未找到扫码开门小程序码链接");
}
// 更新上传人脸小程序码
boolean hasUploadFaceQrcode = deviceSelectDataManager.hasUploadFaceMiniQrcodeUrl();
if (hasUploadFaceQrcode) {
String uploadFaceQrcodeUrl = deviceSelectDataManager.getUploadFaceMiniQrcodeUrl();
if (uploadFaceQrcodeUrl != null && !uploadFaceQrcodeUrl.isEmpty()) {
// 在主线程中更新UI
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
// 使用Glide加载网络图片
if (imgMiniProgramCode != null) {
com.bumptech.glide.Glide.with(OXFaceOnlineActivity.this)
.load(uploadFaceQrcodeUrl)
.into(imgMiniProgramCode);
LogManager.logInfo(TAG, "上传人脸小程序码更新成功: " + uploadFaceQrcodeUrl);
} else {
LogManager.logWarning(TAG, "上传人脸小程序码ImageView为空");
}
} catch (Exception e) {
LogManager.logError(TAG, "更新上传人脸小程序码异常: " + e.getMessage(), e);
}
}
});
} else {
LogManager.logWarning(TAG, "上传人脸小程序码URL为空");
}
} else {
LogManager.logDebug(TAG, "未找到上传人脸小程序码链接");
}
} catch (Exception e) {
LogManager.logError(TAG, "获取小程序码异常: " + e.getMessage(), e);
}
}
/**
* 获取并显示店铺名称
*/
private void loadAndDisplayStoreName() {
try {
DeviceSelectDataManager deviceDataManager = DeviceSelectDataManager.getInstance(this);
String[] storeInfo = deviceDataManager.getStoreInfo();
String storeName = storeInfo[0]; // 第一个元素是店铺名称
if (storeName != null && !storeName.isEmpty()) {
// 根据VenueSceneUtils.isLeaveScene来区分进场或离场
if (VenueSceneUtils.isLeaveScene(this)) {
// 离场场景
tvStoreName.setText("离场 | " + storeName);
} else {
// 进场场景
tvStoreName.setText("进场 | " + storeName);
}
LogManager.logInfo(TAG, "成功显示店铺名称: " + storeName);
} else {
// 根据VenueSceneUtils.isLeaveScene来区分进场或离场
if (VenueSceneUtils.isLeaveScene(this)) {
// 离场场景
tvStoreName.setText("离场 | 未获取到店铺名称");
} else {
// 进场场景
tvStoreName.setText("进场 | 未获取到店铺名称");
}
LogManager.logWarning(TAG, "未获取到店铺名称");
}
} catch (Exception e) {
// 根据VenueSceneUtils.isLeaveScene来区分进场或离场
if (VenueSceneUtils.isLeaveScene(this)) {
// 离场场景
tvStoreName.setText("离场 | 店铺名称获取失败");
} else {
// 进场场景
tvStoreName.setText("进场 | 店铺名称获取失败");
}
LogManager.logError(TAG, "获取店铺名称失败", e);
}
}
/**
* 处理店铺名称点击事件
*/
private void handleStoreNameClick() {
long currentTime = System.currentTimeMillis();
// 如果距离上次点击时间超过1秒,重置计数器
if (currentTime - lastStoreNameClickTime > CLICK_INTERVAL) {
storeNameClickCount = 0;
}
storeNameClickCount++;
lastStoreNameClickTime = currentTime;
LogManager.logDebug(TAG, "店铺名称被点击,当前计数: " + storeNameClickCount);
// 如果连续点击达到5次
if (storeNameClickCount >= MAX_CLICK_COUNT) {
LogManager.logInfo(TAG, "连续点击5次店铺名称,准备返回主界面");
Toast.makeText(this, "即将返回主界面", Toast.LENGTH_SHORT).show();
// 重置计数器
storeNameClickCount = 0;
// 延迟一段时间后返回主界面
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
returnToMainActivity();
}
}, 500); // 延迟0.5秒后返回
} else if (storeNameClickCount >= 3) {
// 当点击次数达到3次时,提示用户还需几次点击
int remainingClicks = MAX_CLICK_COUNT - storeNameClickCount;
Toast.makeText(this, "再点击" + remainingClicks + "次返回主界面", Toast.LENGTH_SHORT).show();
}
}
/**
* 返回主界面
*/
private void returnToMainActivity() {
LogManager.logInfo(TAG, "返回主界面");
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
}
/**
* 处理验证码Activity返回结果
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 处理华为扫码结果
boolean handled = com.ouxuan.oxface.device.HuaWeiScanManager.handleScanResult(requestCode, resultCode, data, new com.ouxuan.oxface.device.HuaWeiScanManager.ScanResultListener() {
@Override
public void onScanSuccess(String scanResult) {
LogManager.logInfo(TAG, "华为扫码成功,结果: " + scanResult);
Log.d(TAG, "扫码结果: " + scanResult);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OXFaceOnlineActivity.this, "扫码成功: " + scanResult, Toast.LENGTH_SHORT).show();
// 调用checkOrder函数进行扫码核销
performScanVerification();
}
});
}
@Override
public void onScanFailed(int errorCode, String errorMsg) {
LogManager.logError(TAG, "华为扫码失败,错误码: " + errorCode + ", 错误信息: " + errorMsg);
Log.e(TAG, "扫码失败,错误码: " + errorCode + ", 错误信息: " + errorMsg);
// 恢复摄像头预览
resumeCamera();
LogManager.logInfo(TAG, "扫码失败,已恢复摄像头预览");
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OXFaceOnlineActivity.this, "扫码失败: " + errorMsg, Toast.LENGTH_SHORT).show();
}
});
}
});
if (handled) {
// 如果已经处理了扫码结果,也需要恢复摄像头预览
if (requestCode == com.ouxuan.oxface.device.HuaWeiScanManager.REQUEST_CODE_SCAN) {
resumeCamera();
LogManager.logInfo(TAG, "华为扫码完成,已恢复摄像头预览");
}
return; // 如果已经处理了扫码结果,则直接返回
}
if (requestCode == 1001) { // 验证码验证获取输入结果
// 恢复摄像头预览
resumeCamera();
LogManager.logInfo(TAG, "恢复摄像头预览 - 使用resumeCamera方法");
if (resultCode == RESULT_OK && data != null) {
String verificationCode = data.getStringExtra("verification_code");
if (verificationCode != null && verificationCode.length() == 12) {
LogManager.logInfo(TAG, "收到验证码: " + verificationCode);
android.util.Log.d("MainActivity", "收到验证码"+verificationCode);
handleVerificationCodeSubmit(verificationCode);
}
} else if (resultCode == RESULT_CANCELED) {
LogManager.logInfo(TAG, "用户点击关闭验证码弹窗");
} else {
LogManager.logInfo(TAG, "用户取消验证码输入");
}
} else if (requestCode == 1002) { // 订单选择页面返回结果
// 恢复摄像头预览
resumeCamera();
LogManager.logInfo(TAG, "恢复摄像头预览 - 使用resumeCamera方法");
if (resultCode == RESULT_OK && data != null) {
// 处理订单选择结果
String selectedOrderJson = data.getStringExtra("selected_order");
String orderNo = data.getStringExtra("order_no");
String verificationCode = data.getStringExtra("verification_code");
int orderType = data.getIntExtra("order_type", 0);
String cardNo = data.getStringExtra("card_no");
String project = data.getStringExtra("project");
int verificationType = data.getIntExtra("verification_type", 2);
LogManager.logInfo(TAG, "订单选择成功: " + orderNo);
// 显示成功状态
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText("订单核销成功");
// 3秒后隐藏状态提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
}, 3000);
}
} else if (resultCode == RESULT_CANCELED) {
LogManager.logInfo(TAG, "用户取消订单选择");
}
}
}
/**
* 处理验证码提交
*/
private void handleVerificationCodeSubmit(String verificationCode) {
// 设置验证码验证模式
modeType = OrderVerificationManager.TYPE_VERIFICATION_CODE;
verifyCode = verificationCode;
// 调用订单查询方法进行验证码验证
getCheckOrder();
}
/**
* 查询并显示当前应用的内存信息
*/
private void displayMemoryInfo() {
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory() / (1024 * 1024); // MB
long totalMemory = runtime.totalMemory() / (1024 * 1024); // MB
long freeMemory = runtime.freeMemory() / (1024 * 1024); // MB
long usedMemory = totalMemory - freeMemory; // MB
// 获取系统内存信息(需要API 16及以上)
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
long totalMem = memoryInfo.totalMem / (1024 * 1024); // MB
long availMem = memoryInfo.availMem / (1024 * 1024); // MB
long threshold = memoryInfo.threshold / (1024 * 1024); // MB
boolean isLowMemory = memoryInfo.lowMemory;
// 构建内存信息字符串
StringBuilder memoryInfoStr = new StringBuilder();
memoryInfoStr.append("应用内存信息:\n");
memoryInfoStr.append("最大可用内存: ").append(maxMemory).append(" MB\n");
memoryInfoStr.append("已分配内存: ").append(totalMemory).append(" MB\n");
memoryInfoStr.append("已使用内存: ").append(usedMemory).append(" MB\n");
memoryInfoStr.append("空闲内存: ").append(freeMemory).append(" MB\n\n");
memoryInfoStr.append("系统内存信息:\n");
memoryInfoStr.append("总内存: ").append(totalMem).append(" MB\n");
memoryInfoStr.append("可用内存: ").append(availMem).append(" MB\n");
memoryInfoStr.append("内存阈值: ").append(threshold).append(" MB\n");
memoryInfoStr.append("低内存状态: ").append(isLowMemory ? "是" : "否");
// 显示内存信息(可以通过Toast或者对话框显示)
Toast.makeText(this, memoryInfoStr.toString(), Toast.LENGTH_LONG).show();
// 同时输出到日志
LogManager.logInfo(TAG, "内存信息:\n" + memoryInfoStr.toString());
}
/**
* 获取当前应用内存使用情况的简要信息
* @return 内存使用情况字符串
*/
private String getMemoryUsageSummary() {
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory() / (1024 * 1024); // MB
long totalMemory = runtime.totalMemory() / (1024 * 1024); // MB
long freeMemory = runtime.freeMemory() / (1024 * 1024); // MB
long usedMemory = totalMemory - freeMemory; // MB
float memoryUsageRatio = (float) usedMemory / maxMemory;
return String.format("内存: %d/%d MB (%.1f%%)",
usedMemory, maxMemory, memoryUsageRatio * 100);
}
/**
* 获取认证Token(统一认证方式)
* @return Token字符串
*/
private String getAuthToken() {
return loginDataManager.getAuthToken();
}
/**
* 查验订单列表
* 根据modeType和verifyCode等参数获取相应的数据查询参数并发送网络请求
*/
private void getCheckOrder() {
LogManager.logInfo(TAG, "开始查验订单列表,modeType: " + modeType);
// 人脸验证模式下不需要暂停摄像头,保持视频流继续运行
if (modeType != OrderVerificationManager.TYPE_FACE_VERIFICATION) {
// 非人脸验证模式(验证码、扫码等)才暂停摄像头
pauseCameraWithTimeout();
}
// 使用新的网络请求管理器执行验证
orderVerificationManager.performVerification(modeType, verifyCode, null);
}
/**
* 处理扫码按钮点击事件
*/
private void handleScanQRClick() {
LogManager.logInfo(TAG, "用户点击扫码按钮");
// 调用华为统一扫码功能
com.ouxuan.oxface.device.HuaWeiScanManager.doScan(this, new com.ouxuan.oxface.device.HuaWeiScanManager.ScanResultListener() {
@Override
public void onScanSuccess(String scanResult) {
// 输出扫码结果到log
LogManager.logInfo(TAG, "华为扫码成功,结果: " + scanResult);
Log.d(TAG, "扫码结果: " + scanResult);
// 显示扫码结果Toast
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OXFaceOnlineActivity.this, "扫码成功: " + scanResult, Toast.LENGTH_SHORT).show();
// 调用checkOrder函数进行扫码核销
performScanVerification();
}
});
}
@Override
public void onScanFailed(int errorCode, String errorMsg) {
LogManager.logError(TAG, "华为扫码失败,错误码: " + errorCode + ", 错误信息: " + errorMsg);
Log.e(TAG, "扫码失败,错误码: " + errorCode + ", 错误信息: " + errorMsg);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OXFaceOnlineActivity.this, "扫码失败: " + errorMsg, Toast.LENGTH_SHORT).show();
}
});
}
});
}
/**
* 处理扫码器开门点击事件
*/
private void handleScannerDoorClick() {
LogManager.logInfo(TAG, "用户点击扫码器开门");
// 检查是否有正在进行的人脸识别请求
if (orderVerificationManager != null && orderVerificationManager.isRequestInProgress()) {
LogManager.logInfo(TAG, "有正在进行的订单验证请求,取消扫码操作");
Toast.makeText(this, "正在处理其他请求,请稍后再试", Toast.LENGTH_SHORT).show();
return;
}
// 暂停摄像头预览
pauseCameraWithTimeout();
LogManager.logInfo(TAG, "已暂停摄像头预览");
// 调用华为统一扫码功能
com.ouxuan.oxface.device.HuaWeiScanManager.doScan(this, new com.ouxuan.oxface.device.HuaWeiScanManager.ScanResultListener() {
@Override
public void onScanSuccess(String scanResult) {
LogManager.logInfo(TAG, "华为扫码器扫码成功,结果: " + scanResult);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OXFaceOnlineActivity.this, "扫码成功: " + scanResult, Toast.LENGTH_SHORT).show();
// 设置模式为4(扫码器验证)
modeType = OrderVerificationManager.TYPE_SCANNER_VERIFICATION;
verifyCode = scanResult;
// 执行扫码器核销(注意:getCheckOrder会再次暂停摄像头,所以我们不需要在这里恢复)
getCheckOrder();
}
});
}
@Override
public void onScanFailed(int errorCode, String errorMsg) {
LogManager.logError(TAG, "华为扫码器扫码失败,错误码: " + errorCode + ", 错误信息: " + errorMsg);
// 恢复摄像头预览
resumeCamera();
LogManager.logInfo(TAG, "扫码失败,已恢复摄像头预览");
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OXFaceOnlineActivity.this, "扫码失败: " + errorMsg, Toast.LENGTH_SHORT).show();
// 显示状态提示
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#FF0000"));
textCompareStatus.setText("扫码失败: " + errorMsg);
// 3秒后隐藏状态提示
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
}, 3000);
}
}
});
}
});
}
/**
* 执行扫码核销
*/
private void performScanVerification() {
// 设置模式为3(扫码验证)
modeType = OrderVerificationManager.TYPE_SCAN_VERIFICATION;
// 调用订单查询方法进行扫码验证
getCheckOrder();
}
/**
* 显示加载状态
*/
private void showLoadingStatus(String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText(message);
}
}
});
}
/**
* 隐藏加载状态
*/
private void hideLoadingStatus() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.GONE);
}
}
});
}
/**
* 显示Toast消息
*/
private void showToast(String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(OXFaceOnlineActivity.this, message, Toast.LENGTH_SHORT).show();
}
});
}
/**
* 初始化摄像头控制广播接收器
*/
private void initCameraControlReceiver() {
cameraControlReceiver = new CameraControlReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.ouxuan.oxface.ACTION_PAUSE_CAMERA");
filter.addAction("com.ouxuan.oxface.ACTION_RESUME_CAMERA");
registerReceiver(cameraControlReceiver, filter);
LogManager.logInfo(TAG, "摄像头控制广播接收器已注册");
}
/**
* 摄像头控制广播接收器
*/
private class CameraControlReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ("com.ouxuan.oxface.ACTION_PAUSE_CAMERA".equals(action)) {
// 暂停摄像头预览
pauseCameraWithTimeout();
LogManager.logInfo(TAG, "接收到暂停摄像头预览广播");
} else if ("com.ouxuan.oxface.ACTION_RESUME_CAMERA".equals(action)) {
// 恢复摄像头预览
resumeCamera();
LogManager.logInfo(TAG, "接收到恢复摄像头预览广播");
}
}
}
/**
* 暂停摄像头并设置超时恢复
*/
private void pauseCameraWithTimeout() {
pauseRequestCount++;
isCameraPausedByDialog = true;
isNeedCamera = false;
// 取消之前的超时任务
if (cameraTimeoutHandler != null) {
cameraTimeoutHandler.removeCallbacksAndMessages(null);
}
// 设置新的超时任务
cameraTimeoutHandler = new Handler();
cameraTimeoutHandler.postDelayed(new Runnable() {
@Override
public void run() {
LogManager.logWarning(TAG, "摄像头暂停超时,自动恢复并关闭所有对话框");
forceResumeAndCloseAllDialogs();
}
}, CAMERA_RESUME_TIMEOUT);
LogManager.logInfo(TAG, "摄像头已暂停,请求计数: " + pauseRequestCount + ", 超时时间: " + CAMERA_RESUME_TIMEOUT + "ms");
}
/**
* 恢复摄像头
*/
private void resumeCamera() {
if (pauseRequestCount > 0) {
pauseRequestCount--;
}
// 只有当所有暂停请求都结束时才恢复
if (pauseRequestCount <= 0) {
isCameraPausedByDialog = false;
isNeedCamera = true;
pauseRequestCount = 0; // 确保不为负数
// 取消超时任务
if (cameraTimeoutHandler != null) {
cameraTimeoutHandler.removeCallbacksAndMessages(null);
cameraTimeoutHandler = null;
}
LogManager.logInfo(TAG, "摄像头已恢复");
} else {
LogManager.logInfo(TAG, "仍有暂停请求,暂不恢复摄像头,剩余请求数: " + pauseRequestCount);
}
}
/**
* 执行离场校验
* @param faceBase64 人脸base64数据
*/
private void performLeaveVerification(String faceBase64) {
LogManager.logInfo(TAG, "开始执行离场校验");
// 离场校验使用人脸识别,不需要暂停摄像头,保持视频流继续运行
// 调用离场校验管理器执行人脸离场校验
if (leaveVerificationManager != null) {
leaveVerificationManager.performFaceLeaveVerification(faceBase64);
} else {
LogManager.logError(TAG, "离场校验管理器未初始化");
showToast("离场校验服务未初始化");
}
}
/**
* 强制恢复摄像头并关闭所有对话框(超时后调用)
*/
private void forceResumeAndCloseAllDialogs() {
// 强制恢复摄像头
isCameraPausedByDialog = false;
isNeedCamera = true;
pauseRequestCount = 0;
// 取消超时任务
if (cameraTimeoutHandler != null) {
cameraTimeoutHandler.removeCallbacksAndMessages(null);
cameraTimeoutHandler = null;
}
// 关闭所有可能的对话框(发送广播通知所有Activity关闭)
try {
Intent intent = new Intent("com.ouxuan.oxface.ACTION_FORCE_CLOSE_DIALOGS");
sendBroadcast(intent);
LogManager.logInfo(TAG, "已发送强制关闭对话框广播");
} catch (Exception e) {
LogManager.logError(TAG, "发送强制关闭对话框广播失败", e);
}
LogManager.logWarning(TAG, "摄像头已强制恢复,所有对话框已关闭");
}
/**
* 检查网络是否可用
* @return true 如果网络可用,false 否则
*/
private boolean isNetworkAvailable() {
try {
// 使用NetworkUtils检查网络连接状态
if (!com.blankj.utilcode.util.NetworkUtils.isConnected()) {
LogManager.logWarning(TAG, "网络未连接");
return false;
}
// 进一步检查网络质量(可选)
if (networkStatusIndicator != null) {
NetworkStatusIndicator.NetworkStatus currentStatus = networkStatusIndicator.getCurrentNetworkStatus();
if (currentStatus == NetworkStatusIndicator.NetworkStatus.POOR) {
LogManager.logWarning(TAG, "网络状态不佳:" + currentStatus.getDescription());
return false;
}
}
LogManager.logDebug(TAG, "网络状态正常");
return true;
} catch (Exception e) {
LogManager.logError(TAG, "检查网络状态失败", e);
return false;
}
}
}