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() { // 增强日志:记录当前场景信息 boolean isCurrentLeaveScene = false; try { isCurrentLeaveScene = com.ouxuan.oxface.utils.VenueSceneUtils.isLeaveScene(OXFaceOnlineActivity.this); } catch (Exception e) { LogManager.logError(TAG, "获取场景信息失败", e); } String sceneInfo = isCurrentLeaveScene ? "离场场景" : "进场场景"; LogManager.logInfo(TAG, "门禁不可用弹窗显示,暂停摄像头和中断操作 - " + sceneInfo); // 暂停摄像头和中断其他操作 pauseCameraWithTimeout(); LogManager.logInfo(TAG, "摄像头暂停完成 - " + sceneInfo); } @Override public void onDialogHide() { // 增强日志:记录当前场景信息 boolean isCurrentLeaveScene = false; try { isCurrentLeaveScene = com.ouxuan.oxface.utils.VenueSceneUtils.isLeaveScene(OXFaceOnlineActivity.this); } catch (Exception e) { LogManager.logError(TAG, "获取场景信息失败", e); } String sceneInfo = isCurrentLeaveScene ? "离场场景" : "进场场景"; LogManager.logInfo(TAG, "门禁不可用弹窗隐藏,恢复摄像头和操作 - " + sceneInfo); // 恢复摄像头和操作 resumeCamera(); LogManager.logInfo(TAG, "摄像头恢复完成 - " + sceneInfo); } @Override public void onDialogClosed() { LogManager.logInfo(TAG, "门禁不可用弹窗关闭,恢复正常门禁监控"); // 人数异常弹窗关闭后,恢复正常的门禁监控状态 try { if (gateABController != null) { // 修复关键问题:无论UDP是否初始化,都需要重新初始化来重置状态缓存 LogManager.logInfo(TAG, "重新初始化UDP门禁控制以重置状态缓存"); gateABController.reinitializeUDP(); // 稍等片刻后启动轮询,确保初始化完成 new Handler(Looper.getMainLooper()).postDelayed(() -> { if (gateABController != null) { gateABController.startUDPPolling(); LogManager.logInfo(TAG, "UDP门禁状态轮询已重新启动,状态缓存已重置"); } }, 500); 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; // 离场网络中断检测逻辑:检测(当前是离场&&当前网络中断){直接执行openGateAB,而不再继续执行后续逻辑} try { boolean isLeaveScene = VenueSceneUtils.isLeaveScene(this); boolean isNetworkAvailable = isNetworkAvailable(); if (isLeaveScene && !isNetworkAvailable) { LogManager.logInfo(TAG, "检测到离场场景且网络中断,直接执行openGateAB开门"); // 直接执行AB门开门操作 if (gateABController != null) { // 暂停摄像头预览10秒后再恢复,避免频繁执行开门操作 pauseCameraWithTimeout(); LogManager.logInfo(TAG, "暂停摄像头预览10秒,避免频繁执行开门操作"); // 10秒后恢复摄像头预览 new Handler().postDelayed(new Runnable() { @Override public void run() { resumeCamera(); LogManager.logInfo(TAG, "10秒后恢复摄像头预览"); } }, 10000); gateABController.openGateAB(new GateABController.GateControlCallback() { @Override public void onSuccess(String message) { LogManager.logInfo(TAG, "离场网络中断直接开门成功: " + message); // 显示简单的成功提示 runOnUiThread(() -> { showLoadingStatus("开门成功,网络异常"); // 5秒后隐藏提示 new Handler().postDelayed(() -> { hideLoadingStatus(); }, 5000); }); } @Override public void onError(String errorMessage) { LogManager.logError(TAG, "离场网络中断直接开门失败: " + errorMessage); // 显示错误提示 runOnUiThread(() -> { showLoadingStatus("开门失败: " + errorMessage); // 5秒后隐藏提示 new Handler().postDelayed(() -> { hideLoadingStatus(); }, 5000); }); } }); } else { LogManager.logError(TAG, "gateABController为空,无法执行开门操作"); } // 直接返回,不再继续执行后续逻辑 return; } LogManager.logInfo(TAG, "继续执行正常的人脸识别流程 - 场景: " + (isLeaveScene ? "离场" : "进场") + ", 网络: " + (isNetworkAvailable ? "可用" : "不可用")); } catch (Exception e) { LogManager.logError(TAG, "离场网络中断检测异常,继续正常流程", e); } // 当未检测到人脸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 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; } } }