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.

3756 lines
168 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 java.util.ArrayList;
import java.util.List;
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.device.DeviceUtils;
import com.ouxuan.oxface.device.OxPadBar;
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.network.api.PadApiService;
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 com.ouxuan.oxface.device.voice.VoicePlayerManager;
import com.ouxuan.oxface.device.voice.VoiceType;
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 final int PREFER_WIDTH = 1280;
// private static final int PERFER_HEIGH = 720;
// 新增控制变量
private static int PROCESS_FRAME_INTERVAL = 2; // 快速处理频率,每隔3帧处理一次
private int frameCounter = 0;
private boolean needSendFaceImage = false; // 是否需要将人脸图片转为base64发送
private long lastProcessTime = 0;
private long lastBackgroundProcessTime = 0; // 应用在后台时的最后处理时间
private static long MIN_PROCESS_INTERVAL = 300; // 快速处理间隔300ms
// 智能调节处理频率的控制变量
private static final int FAST_PROCESS_FRAME_INTERVAL = 2; // 快速处理频率:每3帧处理一次
private static final long FAST_MIN_PROCESS_INTERVAL = 300; // 快速处理间隔:300ms
private static final int SLOW_PROCESS_FRAME_INTERVAL = 10; // 慢速处理频率:每30帧处理一次
private static final long SLOW_MIN_PROCESS_INTERVAL = 2000; // 慢速处理间隔:3000ms
private static final long FACE_DETECTION_TIMEOUT = 8000; // 人脸检测超时时间:5秒
private long lastFaceDetectedTime = 0; // 上次检测到人脸的时间
private boolean isFaceDetected = false; // 当前是否检测到人脸
private int consecutiveNoFaceCount = 0; // 连续未检测到人脸的次数
private static final int CONSECUTIVE_NO_FACE_THRESHOLD = 20; // 连续未检测到人脸的阈值
// FPS统计相关变量
private long lastFpsCheckTime = 0; // 上次检查FPS的时间
private int frameCountInSecond = 0; // 每秒内的帧数计数
private float currentFps = 0; // 当前FPS值
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 TextView tvScanDoorText; // 扫码开门文本
private Button btnVerificationCode;
private Button btnScannerDoor;
// 新增店铺名称相关变量
private TextView tvStoreName;
private int storeNameClickCount = 0;
private long lastStoreNameClickTime = 0;
private static final int MAX_CLICK_COUNT = 1; // 修改为6次
private static final long CLICK_INTERVAL = 1000; // 1秒内点击有效
// 新增解锁密码弹窗相关变量
private com.ouxuan.oxface.device.UnlockPasswordDialog unlockPasswordDialog;
// 新增订单查验相关变量
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; // 60秒超时
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门检测是否开启
// 新增语音播放管理器
private VoicePlayerManager voicePlayerManager;
// 动态人数检测相关变量
private boolean isDynamicPeopleDetectionEnabled = false; // 是否开启动态人数检测
private boolean isDynamicPeopleDetectionRunning = false; // 动态检测是否正在运行
private List<Integer> peopleDetectionResults = new ArrayList<>(); // 检测结果数组
private int gateLoopCountPeopleTimes = 0; // 防尾随记次
private Handler dynamicDetectionHandler = new Handler(Looper.getMainLooper()); // 动态检测Handler
private Runnable dynamicDetectionRunnable; // 动态检测任务
private static final int MAX_DETECTION_COUNT = 100; // 最大检测次数
private int currentDetectionCount = 0; // 当前检测次数
private boolean hasPlayedPeopleAnomalyVoice = false; // 是否已经播放过人数异常语音提醒
private boolean hasShownPeopleAnomalyDialog = false; // 是否已经显示过人数异常弹窗
// 方案二:添加状态标识控制订单选择页面的显示,避免重复弹出
private static boolean isOrderSelectionActivityShowing = false; // 订单选择页面是否正在显示
private static boolean isOrderVerificationResultActivityShowing = false; // 订单核销结果页面是否正在显示
public static boolean isVerificationCodeActivityShowing = false; // 验证码页面是否正在显示
// 设备类型相关变量
private int deviceType = -1; // 设备类型:5表示第6批,6表示第7批,7表示第8批等
@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开始");
// 方案二:初始化订单选择页面显示状态
isOrderSelectionActivityShowing = false;
mContext = this;
// 初始化LoginDataManager
loginDataManager = com.ouxuan.oxface.data.LoginDataManager.getInstance(this);
// 获取设备类型
deviceType = DeviceSelectDataManager.getInstance(this).getDeviceType();
Log.d(TAG, "OXFaceOnlineActivity初始化设备类型: " + deviceType);
// 初始化网络请求管理器
initNetworkManagers();
// 初始化离场校验管理器
initLeaveVerificationManager();
// 初始化摄像头控制广播接收器
initCameraControlReceiver();
// 初始化解锁密码弹窗
initUnlockPasswordDialog();
// 初始化语音播放管理器
initVoicePlayerManager();
initView();
// 初始化网络状态指示器
initNetworkStatusIndicator();
// 初始化AB门禁管理和不可用弹窗
initGateUnavailableDialog();
initHideStateBar();
// 初始化人脸检测状态
lastFaceDetectedTime = System.currentTimeMillis();
isFaceDetected = false;
consecutiveNoFaceCount = 0;
// 初始化处理频率为快速模式,避免启动时的延迟
PROCESS_FRAME_INTERVAL = FAST_PROCESS_FRAME_INTERVAL;
MIN_PROCESS_INTERVAL = FAST_MIN_PROCESS_INTERVAL;
LogManager.logInfo(TAG, "初始化处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms");
// 检查并请求相机权限
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 initHideStateBar(){
// 隐藏状态栏和导航栏
OxPadBar.hidePadBar(this);
}
//解锁状态栏
private void releaseHideStateBar(){
// 显示状态栏和导航栏
OxPadBar.showPadBar(this);
}
/**
* 初始化离场校验管理器
*/
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() {
// 离场校验完成后不立即恢复摄像头,等待结果页面关闭后再恢复
// 因为即将跳转到核销结果页面,需要保持摄像头暂停状态
LogManager.logInfo(TAG, "离场校验完成,等待结果页面关闭后恢复摄像头");
}
@Override
public void showToast(String message) {
OXFaceOnlineActivity.this.showToast(message);
}
@Override
public void showLeaveVerificationResultPage(int errorCode, String errorMessage, boolean isSuccess, PadApiService.CheckLeaveResult result, int verificationType) {
// 跳转到离场校验结果页面
runOnUiThread(() -> {
try {
Intent intent = new Intent(OXFaceOnlineActivity.this, OrderVerificationResultActivity.class);
// 设置验证类型
intent.putExtra("verification_type", verificationType);
// 设置结果状态
if (isSuccess) {
intent.putExtra("status", "离场成功");
// 修复:使用result.getMessage()而不是errorMessage来显示服务端返回的完整消息
intent.putExtra("message", result != null && result.getMessage() != null ? result.getMessage() : "离场成功");
} else {
intent.putExtra("status", "离场失败");
intent.putExtra("message", errorMessage != null ? errorMessage : "离场失败");
}
// 设置错误代码
intent.putExtra("error_code", errorCode);
// 如果有结果数据,传入相关信息
if (result != null) {
// CheckLeaveResult只有message和data属性,没有orderNo和project
// 使用默认值
intent.putExtra("order_no", "");
intent.putExtra("project", "离场验证");
} else {
intent.putExtra("order_no", "");
intent.putExtra("project", "离场验证");
}
// 设置默认值
intent.putExtra("order_type", 0); // 默认订单类型
intent.putExtra("verification_code", "");
intent.putExtra("card_no", "");
LogManager.logInfo(TAG, "跳转到离场校验结果页面,状态: " + (isSuccess ? "成功" : "失败") + ", 错误代码: " + errorCode + ", 验证类型: " + verificationType);
startActivity(intent);
} catch (Exception e) {
LogManager.logError(TAG, "跳转到离场校验结果页面失败", e);
// 如果跳转失败,回退到显示toast的方式
showToast(errorMessage != null ? errorMessage : (isSuccess ? "离场成功" : "离场失败"));
}
});
}
});
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) {
// 人脸识别开始,停止动态人数检测
onFaceRecognitionStarted();
// 直接处理页面跳转逻辑,不在这里开门
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) {
// 方案二:检查订单选择页面是否已经显示,避免重复弹出
if (isOrderSelectionActivityShowing) {
LogManager.logInfo(TAG, "订单选择页面已经在显示中,避免重复启动");
return;
}
// 设置标识为true,表示订单选择页面即将显示
isOrderSelectionActivityShowing = true;
// 在跳转到订单选择页面时暂停摄像头
// pauseCameraWithTimeout();
pauseCamera();
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
}
@Override
public void pauseCamera() {
OXFaceOnlineActivity.this.pauseCamera();
}
@Override
public void resumeCamera() {
OXFaceOnlineActivity.this.resumeCamera();
}
});
}
/**
* 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);
tvScanDoorText = findViewById(R.id.tv_scan_door_text); // 初始化扫码开门文本
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 updateButtonVisibility() {
try {
// 使用VenueSceneUtils工具类获取按钮显示配置
com.ouxuan.oxface.utils.VenueSceneUtils.PadConfigButtonVisibility buttonVisibility =
com.ouxuan.oxface.utils.VenueSceneUtils.getPadConfigButtonVisibility(this);
// 控制开门按钮显示/隐藏
// data.pad_config.is_show_gate_btn == 1 显示开门按钮
if (btnOpenDoor != null) {
btnOpenDoor.setVisibility(buttonVisibility.isShowGateBtn ? View.VISIBLE : View.GONE);
LogManager.logInfo(TAG, "开门按钮显示状态更新: " + (buttonVisibility.isShowGateBtn ? "显示" : "隐藏"));
}
// 控制验证码开门按钮显示/隐藏
// data.pad_config.is_code_verify == 1 开启验证码验证
if (btnVerificationCode != null) {
btnVerificationCode.setVisibility(buttonVisibility.isCodeVerify ? View.VISIBLE : View.GONE);
LogManager.logInfo(TAG, "验证码开门按钮显示状态更新: " + (buttonVisibility.isCodeVerify ? "显示" : "隐藏"));
}
// 控制扫码器开门按钮显示/隐藏
// data.pad_config.is_scan_code_verify == 1 扫码器验证
if (btnScannerDoor != null) {
btnScannerDoor.setVisibility(buttonVisibility.isScanCodeVerify ? View.VISIBLE : View.GONE);
LogManager.logInfo(TAG, "扫码器开门按钮显示状态更新: " + (buttonVisibility.isScanCodeVerify ? "显示" : "隐藏"));
}
// 控制扫码开门按钮显示/隐藏
// data.pad_config.is_scan_verify == 1 扫码开门验证
if (imgScanDoorQRCode != null) {
imgScanDoorQRCode.setVisibility(buttonVisibility.isScanVerify ? View.VISIBLE : View.GONE);
LogManager.logInfo(TAG, "扫码开门按钮显示状态更新: " + (buttonVisibility.isScanVerify ? "显示" : "隐藏"));
}
// 控制扫码开门文本显示/隐藏(与扫码开门按钮一致)
if (tvScanDoorText != null) {
tvScanDoorText.setVisibility(buttonVisibility.isScanVerify ? View.VISIBLE : View.GONE);
LogManager.logInfo(TAG, "扫码开门文本显示状态更新: " + (buttonVisibility.isScanVerify ? "显示" : "隐藏"));
}
// 新用户扫码上传人脸按钮始终显示
if (imgMiniProgramCode != null) {
imgMiniProgramCode.setVisibility(View.VISIBLE);
LogManager.logInfo(TAG, "新用户扫码上传人脸按钮始终显示");
}
} catch (Exception e) {
LogManager.logError(TAG, "更新按钮显示状态时发生异常", e);
// 异常情况下显示所有按钮和文本
if (btnOpenDoor != null) btnOpenDoor.setVisibility(View.VISIBLE);
if (btnVerificationCode != null) btnVerificationCode.setVisibility(View.VISIBLE);
if (btnScannerDoor != null) btnScannerDoor.setVisibility(View.VISIBLE);
if (imgScanDoorQRCode != null) imgScanDoorQRCode.setVisibility(View.VISIBLE);
if (tvScanDoorText != null) tvScanDoorText.setVisibility(View.VISIBLE);
if (imgMiniProgramCode != null) imgMiniProgramCode.setVisibility(View.VISIBLE);
}
}
/**
* 初始化网络状态指示器
*/
private void initNetworkStatusIndicator() {
try {
networkStatusIndicator = new NetworkStatusIndicator(this, relativeLayout);
// 设置网络恢复监听器
networkStatusIndicator.setNetworkRecoveryListener(new NetworkStatusIndicator.NetworkRecoveryListener() {
@Override
public void onNetworkRecovered() {
LogManager.logInfo(TAG, "接收到网络恢复通知,恢复摄像头预览");
// 网络恢复时恢复摄像头预览
resumeCamera();
// 检查是否有门禁不可用弹窗显示,如果有则关闭它
if (gateUnavailableDialog != null) {
try {
// 使用反射调用isShowing方法检查弹窗是否显示
java.lang.reflect.Method isShowingMethod = gateUnavailableDialog.getClass().getMethod("isShowing");
boolean isShowing = (Boolean) isShowingMethod.invoke(gateUnavailableDialog);
if (isShowing) {
LogManager.logInfo(TAG, "检测到门禁不可用弹窗正在显示,网络恢复后自动关闭弹窗");
// 使用反射调用hide方法关闭弹窗
java.lang.reflect.Method hideMethod = gateUnavailableDialog.getClass().getMethod("hide");
hideMethod.invoke(gateUnavailableDialog);
LogManager.logInfo(TAG, "门禁不可用弹窗已因网络恢复而关闭");
} else {
LogManager.logDebug(TAG, "门禁不可用弹窗未显示,无需关闭");
}
} catch (Exception e) {
LogManager.logWarning(TAG, "检查或关闭门禁不可用弹窗失败: " + e.getMessage());
}
}
}
@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);
// 初始化门禁不可用弹窗
gateUnavailableDialog = new GateUnavailableDialog(this);
// 检查是否开启AB门检测
checkGateCheckEnabled();
// 只有当AB门检测开启时才设置门状态监听器(触发时机1)
if (isGateCheckEnabled) {
// 设置门状态监听器(触发时机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);
// 检查门禁不可用弹窗是否已初始化
if (gateUnavailableDialog == null) {
LogManager.logError(TAG, "门禁不可用弹窗未初始化,无法显示");
return;
}
// 检查是否应该显示弹窗
boolean shouldShow = gateUnavailableDialog.checkShow(OXFaceOnlineActivity.this, isNetworkAvailable());
if (shouldShow) {
// 获取当前门状态信息
GateABController.GateABState currentState = gateABController.getCurrentGateState();
// 如果已有弹窗存在,更新内容(带门状态信息);如果没有,显示新弹窗
gateUnavailableDialog.updateGateStateError(reason,
currentState.gateAOpen,
currentState.gateBOpen,
currentState.udpConnected);
pauseCamera();
LogManager.logInfo(TAG, " pauseCamera 已更新门禁不可用弹窗内容: " + reason);
} else {
LogManager.logInfo(TAG, "根据业务规则,不显示门禁不可用弹窗");
}
}
@Override
public void onGateAvailable() {
LogManager.logInfo(TAG, "门禁恢复可用,隐藏弹窗并恢复摄像头预览");
// 检查门禁不可用弹窗是否已初始化
if (gateUnavailableDialog == null) {
LogManager.logWarning(TAG, "门禁不可用弹窗未初始化,无法隐藏");
// 直接恢复摄像头预览
resumeCamera();
return;
}
// 隐藏门禁不可用弹窗
if (gateUnavailableDialog != null && gateUnavailableDialog.isShowing()) {
gateUnavailableDialog.hide();
}
// 恢复摄像头预览(与弹窗的onDialogHide回调保持一致)
resumeCamera();
}
@Override
public void onGateStatusUpdate(boolean gateAOpen, boolean gateBOpen, boolean udpConnected) {
// 检查门禁不可用弹窗是否已初始化
if (gateUnavailableDialog == null) {
return;
}
// 实时更新弹窗中的门状态显示
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();
// }
}
});
} else {
LogManager.logInfo(TAG, "AB门检测已关闭,跳过设置门状态监听器(触发时机1)");
}
// 设置门状态变化回调(用于动态人数检测)
gateABController.setGateStateChangeCallback(new GateABController.GateStateChangeCallback() {
@Override
public void onGateClosed() {
// 门关闭时开始动态人数检测 - 直接调用方法避免递归
if (!isDynamicPeopleDetectionRunning) {
LogManager.logInfo(TAG, "检测到门关闭,开始动态人数检测");
startDynamicPeopleDetection();
} else {
LogManager.logInfo(TAG, "动态人数检测已在运行,跳过门关闭触发");
}
}
@Override
public void onGateOpened() {
// 门开启时的处理(暂时不需要)
LogManager.logInfo(TAG, "门开启事件触发");
}
});
// 设置弹窗操作监听器
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);
// 暂停摄像头和中断其他操作
pauseCamera();
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);
}
}
});
// 设置解锁密码弹窗触发器
gateUnavailableDialog.setUnlockTrigger(new GateUnavailableDialog.UnlockPasswordDialogTrigger() {
@Override
public void triggerUnlockPasswordDialog() {
LogManager.logInfo(TAG, "门禁不可用弹窗标题触发解锁密码弹窗");
showUnlockPasswordDialog();
}
});
LogManager.logInfo(TAG, "AB门禁管理和不可用弹窗初始化完成");
} catch (Exception e) {
LogManager.logError(TAG, "AB门禁管理和不可用弹窗初始化失败", e);
}
}
/**
* 显示新的门禁不可用弹窗
* @param reason 不可用原因
*/
private void showNewGateUnavailableDialog(String reason) {
try {
// 检查门禁不可用弹窗是否已初始化
if (gateUnavailableDialog == null) {
LogManager.logError(TAG, "门禁不可用弹窗未初始化,无法显示: " + reason);
return;
}
// 执行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 {
// 检查门禁不可用弹窗是否已初始化
if (gateUnavailableDialog == null) {
LogManager.logError(TAG, "门禁不可用弹窗未初始化,无法显示人数异常弹窗");
return;
}
// 执行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门检测是否开启
boolean gateCheckEnabled = false;
// 获取门禁配置信息
com.ouxuan.oxface.utils.VenueSceneUtils.GateConfig gateConfig =
com.ouxuan.oxface.utils.VenueSceneUtils.getGateConfig(this);
if (gateConfig != null) {
gateCheckEnabled = gateConfig.gateAbEnable;
LogManager.logInfo(TAG, "从配置获取AB门检测状态: " + (gateCheckEnabled ? "已开启" : "已关闭"));
} else {
LogManager.logWarning(TAG, "无法获取门禁配置,AB门检测默认关闭");
gateCheckEnabled = false;
}
isGateCheckEnabled = gateCheckEnabled;
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");
}
// 根据后台配置更新按钮显示状态
updateButtonVisibility();
resumeCamera();
LogManager.logInfo(TAG, "OXFaceOnlineActivity onResume");
}
private void startTestOpenDebugRegisterFunction() {
LogManager.logInfo(TAG, "启动摄像头预览");
try {
//输出SingleBaseConfig.getBaseConfig()
Log.d(TAG, "startTestOpenDebugRegisterFunction: 555:"+ SingleBaseConfig.getBaseConfig());
// 设置摄像头方向
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 {
// Log.d(TAG, "45466: 444:"+isNeedCamera);
frameCounter++;
// // FPS统计逻辑
// frameCountInSecond++;
// // 每秒计算一次FPS
// if (System.currentTimeMillis() - lastFpsCheckTime >= 1000) {
// currentFps = frameCountInSecond;
// LogManager.logInfo(TAG, "摄像头FPS: " + currentFps);
// frameCountInSecond = 0;
// lastFpsCheckTime = System.currentTimeMillis();
// }
// 摄像头预览数据进行人脸检测
if (isNeedCamera) {
// 增加帧计数器和时间间隔控制
// frameCounter++;
long currentTime = System.currentTimeMillis();
// 智能调节处理频率
adjustProcessFrequency(currentTime);
// Log.d(TAG, "frameCounter45466:"+(frameCounter % PROCESS_FRAME_INTERVAL == 0));
// 只有当满足处理条件时才进行人脸检测
if (frameCounter % PROCESS_FRAME_INTERVAL == 0) {
// if(true){
// Log.d(TAG, "满足条件: 0000000:"+isNeedCamera+"|"+needSendFaceImage);
lastProcessTime = currentTime;
// Log.d(TAG, "onGetCameraData: 666:"+FaceSDKManager.initStatus+"帧数阈值:"+SingleBaseConfig.getBaseConfig().getFramesThreshold());
// 检查应用是否处于前台
// if (!isApplicationInForeground()) {
//
// // 如果应用在后台,减少处理频率,每隔10秒处理一次
// if ((currentTime - lastBackgroundProcessTime) < 10000) {
// return;
// }
// lastBackgroundProcessTime = currentTime;
// }
// Log.d(TAG, "isApplicationInForeground: 777:"+isApplicationInForeground());
FaceSDKManager.getInstance().onDetectCheck(data, null, null,
height, width, 1, new FaceDetectCallBack() {
@Override
public void onFaceDetectCallback(LivenessModel livenessModel) {
Log.d(TAG, "onGetCameraData: 获取到人脸:"+livenessModel.getTrackFaceInfo().length+"|height:"+height+"| width:"+width);
try {
// 检查是否需要进行人脸检测
if (!isNeedCheckFace()) {
LogManager.logDebug(TAG, "当前有弹窗覆盖,跳过人脸检测处理");
layoutCompareStatus.setVisibility(View.GONE);//有弹窗时移除提示
showFrame(null);
return;
}
// 更新人脸检测状态
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);
// 绘制人脸框
if (!mAutoCameraPreviewView.isDraw) {
showFrame(livenessModel);
}
} catch (Exception e) {
LogManager.logError(TAG, "人脸框绘制回调处理异常", e);
}
}
});
} else if (frameCounter % 30 == 0 ) {
Log.e(TAG, "每30帧清空一次画布: 11111:");
// 对于跳过处理的帧,每30帧清空一次画布,确保无人脸时画面干净
try {
LivenessModel emptyModel = new LivenessModel();
emptyModel.setTrackFaceInfo(null);
showFrame(emptyModel);
layoutCompareStatus.setVisibility(View.GONE);
} catch (Exception e) {
LogManager.logError(TAG, "清空画布时发生异常", e);
}
}
}else{
// Log.e(TAG, "不满足条件: 0000000:");
showFrame(null);
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; // 重置连续未检测到人脸计数器
Log.e(TAG, "检测到人脸updateFaceDetectionStatus: ");
LogManager.logDebug(TAG, "检测到人脸");
} else {
// 未检测到人脸
consecutiveNoFaceCount++;
// 如果连续多次未检测到人脸,标记为未检测到人脸状态
if (consecutiveNoFaceCount >= CONSECUTIVE_NO_FACE_THRESHOLD) {
isFaceDetected = false;
LogManager.logDebug(TAG, "连续未检测到人脸,当前计数: " + consecutiveNoFaceCount);
Log.e(TAG, "连续未检测到人脸:当前计数 "+consecutiveNoFaceCount);
}
}
}
/**
* 绘制人脸框
*/
private void showFrame(final LivenessModel model) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// Log.d(TAG, "showFrame888:"+model.toString());
Canvas canvas = mDrawDetectFaceView.lockCanvas();
if (canvas == null) {
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
return;
}
// 始终清空canvas
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// 如果没有模型数据,直接返回清空的画布
if (model == null) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
return;
}
// 获取人脸信息
FaceInfo[] faceInfos = model.getTrackFaceInfo();
// 如果没有检测到人脸,直接返回清空的画布
if (faceInfos == null || faceInfos.length == 0) {
// 清空canvas
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
mDrawDetectFaceView.unlockCanvasAndPost(canvas);
return;
}
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// 只在检测到人脸时绘制人脸框
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());
// 根据设备类型进行人脸框坐标适配
if (deviceType == 6) {
// 第7批设备需要180度旋转适配
float screenWidth = mAutoCameraPreviewView.getPreviewWidth();
float screenHeight = mAutoCameraPreviewView.getPreviewHeight();
float tempLeft = rectF.left;
float tempTop = rectF.top;
rectF.left = screenWidth - rectF.right;
rectF.right = screenWidth - tempLeft;
rectF.top = screenHeight - rectF.bottom;
rectF.bottom = screenHeight - tempTop;
Log.d(TAG, "第7批设备人脸框坐标已进行180度旋转适配");
}
if((rectF.right-rectF.left)-(mAutoCameraPreviewView.getPreviewWidth()/3)<0){
Log.d(TAG, "人像过小,不绘制");
continue;
}
// 人脸框颜色
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();
Toast.makeText(this, "请将核销码对准屏幕下方的扫码器", Toast.LENGTH_SHORT).show();
}
}
/**
* 处理扫码按钮点击事件
*/
// 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, "用户点击验证码开门");
// 使用新的暂停摄像头方法
pauseCamera();
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();
releaseHideStateBar();
// 释放语音播放器资源
if (voicePlayerManager != null) {
voicePlayerManager.release();
voicePlayerManager = null;
LogManager.logInfo(TAG, "语音播放器资源已释放");
}
// 销毁网络状态指示器
if (networkStatusIndicator != null) {
networkStatusIndicator.destroy();
networkStatusIndicator = null;
}
// 释放AB门禁管理和不可用弹窗资源
if (gateUnavailableDialog != null) {
gateUnavailableDialog.release();
gateUnavailableDialog = null;
LogManager.logInfo(TAG, "门禁不可用弹窗资源已释放");
}
// 注意:GateABController是全局单例,不应该在这里释放
// 只需要将引用置为null,避免内存泄漏
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 (unlockPasswordDialog != null) {
unlockPasswordDialog.release();
unlockPasswordDialog = null;
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));
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText("未检测到人脸");
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.getFaceInfo().centerY>500){
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#fec133"));
textCompareStatus.setText("请移动人脸置于屏幕中");
return;
}
//通过检测
if (livenessModel != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText("人脸订单检测中");
Log.d(TAG, "人脸订单检测: "+livenessModel.getFaceInfo().score+" | "+livenessModel.getFaceInfo().bestImageScore+ " | "+livenessModel.getFaceInfo().centerX+" | "+livenessModel.getFaceInfo().centerY);
checkResultOnline(livenessModel);//在线人脸检测
} else {
currentLivenessModel = null;
}
}
});
}
private void checkResultOnline(LivenessModel livenessModel) {
this.currentLivenessModel = livenessModel;
if(!isNeedCamera){
LogManager.logInfo(TAG, "摄像头暂停,停止接收livenessModel");
return;
}
// 判断是进场还是离场场景
if (VenueSceneUtils.isLeaveScene(OXFaceOnlineActivity.this)) {
// 离场场景:检查gate_open_enable配置(0922沟通后确认使用gate_open_enable字段)
VenueSceneUtils.GateConfig gateConfig = VenueSceneUtils.getGateConfig(OXFaceOnlineActivity.this);
// 修改为判断gateOpenEnable字段,而不是gateEnterOpenEnable
if (gateConfig != null && gateConfig.gateOpenEnable) {
// 如果 gate_open_enable 为 true,直接开门不进行网络核销
LogManager.logInfo(TAG, "检测到离场场景,gate_open_enable为true,直接开启B门");
showLoadingStatus("门已打开,请直接离场");
// 直接开启B门
if (gateABController != null) {
LogManager.logInfo(TAG, "gate_open_enable为true,直接开启B门");
gateABController.handleFaceRecognitionSuccess(false); // 参数保留兼容性,实际都开B门
}
pauseCamera();
// 5秒后隐藏提示并恢复摄像头
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
hideLoadingStatus();
resumeCamera();
}
}, 5000);
return;
}
}
// 离场网络中断检测逻辑:检测(当前是离场&&当前网络中断){直接执行openGateAB,而不再继续执行后续逻辑}
try {
boolean isLeaveScene = VenueSceneUtils.isLeaveScene(this);
boolean isNetworkAvailable = isNetworkAvailable();
if (isLeaveScene && !isNetworkAvailable) {
LogManager.logInfo(TAG, "检测到离场场景且网络中断,直接执行openGateAB开门");
// 直接执行AB门开门操作
if (gateABController != null) {
// 暂停摄像头预览10秒后再恢复,避免频繁执行开门操作
pauseCamera();
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) {
LogManager.logError(TAG, "livenessModel为空");
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 {
// 执行人数检测
LogManager.logInfo(TAG, "准备调用ABPeopleCheck方法");
boolean peopleCheckPassed = abGateManager.ABPeopleCheck();
LogManager.logInfo(TAG, "ABPeopleCheck方法返回结果: " + peopleCheckPassed);
// peopleCheckPassed = true; //TODO test参数,跳过人脸验证
if (!peopleCheckPassed) {
LogManager.logWarning(TAG, "人数检测未通过,准备显示弹窗");
// 人数检测未通过,显示弹窗
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);
showToast("获取人数失败: " + errorMessage);
// 直接更新弹窗内容,不需要检查重复弹窗
// showNewGateUnavailableDialog("门禁内人数不符合要求,请等待");
}
});
} catch (Exception e) {
LogManager.logError(TAG, "处理人数检测结果异常", e);
}
});
// 人数检测未通过,中断后续的人脸识别流程
LogManager.logInfo(TAG, "AB门人数检测未通过,中断后续人脸识别流程");
return;
} else {
LogManager.logInfo(TAG, "AB门人数棈测通过,继续人脸识别流程");
// AB门检查通过后,开始动态人数检测(防止尾随进入)
if (checkDynamicPeopleDetectionEnabled()) {
LogManager.logInfo(TAG, "AB门检查通过,开始动态人数检测");
startDynamicPeopleDetection();
} else {
LogManager.logInfo(TAG, "动态人数检测功能未开启");
}
}
} 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数据");
// 重置连续未检测到人脸计数器
consecutiveNoFaceCount = 0;
// 保存人脸base64数据到verifyCode变量
verifyCode = base64img;
// 设置模式为2(人脸验证)
modeType = OrderVerificationManager.TYPE_FACE_VERIFICATION;
// 判断是进场还是离场场景
if (VenueSceneUtils.isLeaveScene(OXFaceOnlineActivity.this)) {
// 离场场景:检查gate_open_enable配置(0922沟通后确认使用gate_open_enable字段)
VenueSceneUtils.GateConfig gateConfig = VenueSceneUtils.getGateConfig(OXFaceOnlineActivity.this);
// 修改为判断gateOpenEnable字段,而不是gateEnterOpenEnable
if (gateConfig != null && gateConfig.gateOpenEnable) {
// 如果 gate_open_enable 为 true,直接开门不进行网络核销,该逻辑已转移
} else {
// gate_open_enable 为 false 或配置不存在,按正常流程进行网络校验
if (isNetworkAvailable()) {
LogManager.logInfo(TAG, "检测到离场场景,网络可用,执行离场校验");
// 检查是否已有正在进行的离场验证请求,避免重复请求
if (leaveVerificationManager != null && leaveVerificationManager.isRequestInProgress()) {
LogManager.logInfo(TAG, "已有正在进行的离场验证请求,跳过本次请求");
return;
}
performLeaveVerification(base64img);
}
else {
LogManager.logWarning(TAG, "检测到离场场景,但网络不可用,直接开启B门");
showLoadingStatus("网络不可用,直接开门");
// 直接开启B门,防止用户卡在场内
if (gateABController != null) {
LogManager.logInfo(TAG, "离场场景网络不可用,直接开启B门");
// 检查GateABController是否已经被释放
try {
gateABController.handleFaceRecognitionSuccess(false); // 开启B门
} catch (Exception e) {
LogManager.logError(TAG, "调用GateABController.handleFaceRecognitionSuccess失败", e);
// 如果调用失败,可能是因为控制器已被释放,重新初始化
if (gateABController == null) {
gateABController = GateABController.getInstance();
gateABController.initialize(OXFaceOnlineActivity.this);
gateABController.handleFaceRecognitionSuccess(false);
}
}
}
// 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();
// 成功获取到人脸base64数据时,重置连续未检测到人脸计数器
consecutiveNoFaceCount = 0;
return bitmap_str;
} else {
// 如果不需要发送,则不进行base64转换,直接释放资源
image.destory();
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
Log.d(TAG, "getFaceImageBase64: 释放base64");
return null;
}
}
}
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);
// 如果连续点击达到6次,触发解锁密码弹窗
if (storeNameClickCount >= MAX_CLICK_COUNT) {
LogManager.logInfo(TAG, "连续点击6次店铺名称,触发解锁密码弹窗");
// 重置计数器
storeNameClickCount = 0;
// 显示解锁密码弹窗
showUnlockPasswordDialog();
} else if (storeNameClickCount >= 6) {
// 当点击次数达到3次时,提示用户还需几次点击
int remainingClicks = MAX_CLICK_COUNT - storeNameClickCount;
Toast.makeText(this, "请输入登录密码解锁", Toast.LENGTH_SHORT).show();
}
}
/**
* 初始化解锁密码弹窗
*/
private void initUnlockPasswordDialog() {
unlockPasswordDialog = new com.ouxuan.oxface.device.UnlockPasswordDialog(this);
unlockPasswordDialog.setListener(new com.ouxuan.oxface.device.UnlockPasswordDialog.UnlockDialogListener() {
@Override
public void onUnlockSuccess() {
LogManager.logInfo(TAG, "解锁成功,准备退出人脸识别");
unLockAndLeaveFaceDetect();
}
@Override
public void onDialogShow() {
// 暂停摄像头预览
pauseCamera();
LogManager.logInfo(TAG, "解锁密码弹窗显示,摄像头已暂停");
}
@Override
public void onDialogDismiss() {
// 恢复摄像头预览
resumeCamera();
LogManager.logInfo(TAG, "解锁密码弹窗关闭,摄像头已恢复");
}
});
LogManager.logInfo(TAG, "解锁密码弹窗初始化完成");
}
/**
* 显示解锁密码弹窗
*/
private void showUnlockPasswordDialog() {
if (unlockPasswordDialog != null && !unlockPasswordDialog.isShowing()) {
unlockPasswordDialog.show();
}
}
/**
* 解锁并退出人脸识别界面
*/
private void unLockAndLeaveFaceDetect() {
LogManager.logInfo(TAG, "执行解锁退出操作");
try {
// 停止摄像头预览
// if (CameraPreviewManager.getInstance() != null) {
// CameraPreviewManager.getInstance().stopPreview();
// }
finish();
// 返回登录界面,添加标志表示是从解锁离开返回的
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("from_unlock_leave", true); // 添加标志
startActivity(intent);
// 关闭当前界面
LogManager.logInfo(TAG, "已退出人脸识别界面,返回登录界面");
} catch (Exception e) {
LogManager.logError(TAG, "解锁退出操作失败", e);
Toast.makeText(this, "退出失败,请重试", Toast.LENGTH_SHORT).show();
}
}
/**
* 处理验证码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方法");
// 方案二:重置订单选择页面显示状态
isOrderSelectionActivityShowing = false;
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;
// 判断当前场景
boolean isLeaveScene = VenueSceneUtils.isLeaveScene(this);
if (isLeaveScene) {
// 离场场景:调用离场验证码核销逻辑
LogManager.logInfo(TAG, "离场场景验证码验证,验证码: " + verificationCode);
leaveVerificationManager.performVerification(LeaveVerificationManager.TYPE_VERIFICATION_CODE, verificationCode, null);
} else {
// 进场场景:调用订单查询方法进行验证码验证
LogManager.logInfo(TAG, "进场场景验证码验证,验证码: " + 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();
}
/**
* 初始化语音播放管理器
*/
private void initVoicePlayerManager() {
try {
voicePlayerManager = VoicePlayerManager.getInstance();
voicePlayerManager.initialize(this);
LogManager.logInfo(TAG, "语音播放管理器初始化完成");
} catch (Exception e) {
LogManager.logError(TAG, "语音播放管理器初始化失败", e);
}
}
/**
* 查验订单列表
* 根据modeType和verifyCode等参数获取相应的数据查询参数并发送网络请求
*/
private void getCheckOrder() {
LogManager.logInfo(TAG, "开始查验订单列表,modeType: " + modeType);
// 播放正在进行人脸识别语音
if (voicePlayerManager != null) {
voicePlayerManager.playVoice(VoiceType.FACE_RECOGNITION);
}
// 人脸验证模式下不需要暂停摄像头,保持视频流继续运行
// if (modeType != OrderVerificationManager.TYPE_FACE_VERIFICATION) {
// // 非人脸验证模式(验证码、扫码等)才暂停摄像头
// pauseCameraWithTimeout();
// }
pauseCamera(); //全部模式下都需要进行摄像头暂停
// 使用新的网络请求管理器执行验证
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 handleOpenDoorClick() {
LogManager.logInfo(TAG, "用户点击开门按钮");
// 检查GateABController是否已初始化
if (gateABController == null) {
LogManager.logError(TAG, "GateABController未初始化,无法执行开门操作");
Toast.makeText(this, "门禁控制器未初始化", Toast.LENGTH_SHORT).show();
return;
}
// 显示开门状态
if (layoutCompareStatus != null) {
layoutCompareStatus.setVisibility(View.VISIBLE);
textCompareStatus.setTextColor(Color.parseColor("#009874"));
textCompareStatus.setText("正在开门...");
}
// 执行AB门开门操作
// 检查GateABController是否已经被释放
try {
gateABController.openGateAB(new GateABController.GateControlCallback() {
@Override
public void onSuccess(String message) {
LogManager.logInfo(TAG, "开门成功: " + message);
runOnUiThread(() -> {
Toast.makeText(OXFaceOnlineActivity.this, "开门成功: " + message, Toast.LENGTH_SHORT).show();
// 更新UI状态
if (layoutCompareStatus != null) {
textCompareStatus.setText("开门成功");
textCompareStatus.setTextColor(Color.parseColor("#009874"));
// 3秒后隐藏状态提示
new Handler().postDelayed(() -> {
layoutCompareStatus.setVisibility(View.GONE);
}, 3000);
}
});
}
@Override
public void onError(String errorMessage) {
LogManager.logError(TAG, "开门失败: " + errorMessage);
runOnUiThread(() -> {
Toast.makeText(OXFaceOnlineActivity.this, "开门失败: " + errorMessage, Toast.LENGTH_SHORT).show();
// 更新UI状态
if (layoutCompareStatus != null) {
textCompareStatus.setText("开门失败: " + errorMessage);
textCompareStatus.setTextColor(Color.RED);
// 3秒后隐藏状态提示
new Handler().postDelayed(() -> {
layoutCompareStatus.setVisibility(View.GONE);
}, 3000);
}
});
}
});
} catch (Exception e) {
LogManager.logError(TAG, "调用GateABController.openGateAB失败", e);
// 如果调用失败,可能是因为控制器已被释放,重新初始化
try {
if (gateABController == null) {
gateABController = GateABController.getInstance();
gateABController.initialize(OXFaceOnlineActivity.this);
}
gateABController.openGateAB(new GateABController.GateControlCallback() {
@Override
public void onSuccess(String message) {
LogManager.logInfo(TAG, "开门成功: " + message);
runOnUiThread(() -> {
Toast.makeText(OXFaceOnlineActivity.this, "开门成功: " + message, Toast.LENGTH_SHORT).show();
// 更新UI状态
if (layoutCompareStatus != null) {
textCompareStatus.setText("开门成功");
textCompareStatus.setTextColor(Color.parseColor("#009874"));
// 3秒后隐藏状态提示
new Handler().postDelayed(() -> {
layoutCompareStatus.setVisibility(View.GONE);
}, 3000);
}
});
}
@Override
public void onError(String errorMessage) {
LogManager.logError(TAG, "开门失败: " + errorMessage);
runOnUiThread(() -> {
Toast.makeText(OXFaceOnlineActivity.this, "开门失败: " + errorMessage, Toast.LENGTH_SHORT).show();
// 更新UI状态
if (layoutCompareStatus != null) {
textCompareStatus.setText("开门失败: " + errorMessage);
textCompareStatus.setTextColor(Color.RED);
// 3秒后隐藏状态提示
new Handler().postDelayed(() -> {
layoutCompareStatus.setVisibility(View.GONE);
}, 3000);
}
});
}
});
} catch (Exception reInitException) {
LogManager.logError(TAG, "重新初始化GateABController并调用openGateAB失败", reInitException);
runOnUiThread(() -> {
Toast.makeText(OXFaceOnlineActivity.this, "开门失败: 控制器初始化失败", Toast.LENGTH_SHORT).show();
// 更新UI状态
if (layoutCompareStatus != null) {
textCompareStatus.setText("开门失败: 控制器初始化失败");
textCompareStatus.setTextColor(Color.RED);
// 3秒后隐藏状态提示
new Handler().postDelayed(() -> {
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");
filter.addAction("com.ouxuan.oxface.ACTION_RESET_ORDER_SELECTION_STATUS"); // 添加新的广播动作
filter.addAction("com.ouxuan.oxface.ACTION_ORDER_VERIFICATION_RESULT_SHOWING"); // 订单核销结果页面正在显示
filter.addAction("com.ouxuan.oxface.ACTION_ORDER_VERIFICATION_RESULT_HIDDEN"); // 订单核销结果页面已隐藏
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)) {
// 暂停摄像头预览
pauseCamera();
LogManager.logInfo(TAG, "接收到暂停摄像头预览广播");
} else if ("com.ouxuan.oxface.ACTION_RESUME_CAMERA".equals(action)) {
// 检查是否有订单核销结果页面正在显示,如果有则不恢复摄像头预览
if (isOrderVerificationResultActivityShowing) {
LogManager.logInfo(TAG, "订单核销结果页面正在显示,不恢复摄像头预览");
return;
}
// 恢复摄像头预览
resumeCamera();
LogManager.logInfo(TAG, "接收到恢复摄像头预览广播");
} else if ("com.ouxuan.oxface.ACTION_RESET_ORDER_SELECTION_STATUS".equals(action)) {
// 方案二:重置订单选择页面显示状态
isOrderSelectionActivityShowing = false;
LogManager.logInfo(TAG, "接收到重置订单选择页面显示状态广播");
} else if ("com.ouxuan.oxface.ACTION_ORDER_VERIFICATION_RESULT_SHOWING".equals(action)) {
// 订单核销结果页面正在显示
pauseCamera();
isOrderVerificationResultActivityShowing = true;
LogManager.logInfo(TAG, "接收到订单核销结果页面正在显示广播");
} else if ("com.ouxuan.oxface.ACTION_ORDER_VERIFICATION_RESULT_HIDDEN".equals(action)) {
// 订单核销结果页面已隐藏
isOrderVerificationResultActivityShowing = false;
LogManager.logInfo(TAG, "接收到订单核销结果页面已隐藏广播");
// 恢复摄像头预览
resumeCamera();
LogManager.logInfo(TAG, "订单核销结果页面已隐藏,恢复摄像头预览");
}
}
}
/**
* 暂停摄像头
*/
private void pauseCamera() {
pauseRequestCount++;
isCameraPausedByDialog = true;
isNeedCamera = false;
// 取消之前的超时任务
if (cameraTimeoutHandler != null) {
cameraTimeoutHandler.removeCallbacksAndMessages(null);
}
// 清空一次画布,确保暂停时画面干净
try {
LivenessModel emptyModel = new LivenessModel();
emptyModel.setTrackFaceInfo(null);
showFrame(emptyModel);
} catch (Exception e) {
LogManager.logError(TAG, "清空画布时发生异常", e);
}
// 设置新的超时任务
// cameraTimeoutHandler = new Handler();
// cameraTimeoutHandler.postDelayed(new Runnable() {
// @Override
// public void run() {
// LogManager.logWarning(TAG, "摄像头暂停超时,自动恢复并关闭所有对话框1111111");
// forceResumeAndCloseAllDialogs();
// }
// }, 10000);
LogManager.logInfo(TAG, "摄像头已暂停,请求计数: " + pauseRequestCount + ", 超时时间: " + "ms");
}
/**
* 暂停摄像头并设置超时恢复
*/
private void pauseCameraWithTimeout() {
pauseRequestCount++;
isCameraPausedByDialog = true;
isNeedCamera = false;
// 取消之前的超时任务
if (cameraTimeoutHandler != null) {
cameraTimeoutHandler.removeCallbacksAndMessages(null);
}
// 清空一次画布,确保暂停时画面干净
try {
LivenessModel emptyModel = new LivenessModel();
emptyModel.setTrackFaceInfo(null);
showFrame(emptyModel);
} catch (Exception e) {
LogManager.logError(TAG, "清空画布时发生异常", e);
}
// 设置新的超时任务
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--;
}
pauseRequestCount = 0; //恢复摄像头
// 只有当所有暂停请求都结束时才恢复
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) {
// 2. 播放"正在进行人脸识别"语音
if (voicePlayerManager != null) {
voicePlayerManager.playVoice(VoiceType.FACE_RECOGNITION);
}
leaveVerificationManager.performVerification(LeaveVerificationManager.TYPE_FACE_VERIFICATION, faceBase64, null);
} 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);
}
// 方案二:重置订单选择页面显示状态
isOrderSelectionActivityShowing = false;
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;
}
}
/**
* 检查是否开启动态人数检测功能
*/
private boolean checkDynamicPeopleDetectionEnabled() {
try {
VenueSceneUtils.GateConfig gateConfig = VenueSceneUtils.getGateConfig(this);
return gateConfig != null && gateConfig.gateCameraDetectHardLevel;
} catch (Exception e) {
LogManager.logError(TAG, "检查动态人数检测开关失败", e);
return false;
}
}
/**
* 开始动态人数检测
*/
private void startDynamicPeopleDetection() {
if (!checkDynamicPeopleDetectionEnabled()) {
LogManager.logInfo(TAG, "动态人数检测功能未开启");
return;
}
if (isDynamicPeopleDetectionRunning) {
LogManager.logInfo(TAG, "动态人数检测已在运行中");
return;
}
LogManager.logInfo(TAG, "开始动态人数检测");
// 初始化检测状态
isDynamicPeopleDetectionRunning = true;
peopleDetectionResults.clear();
currentDetectionCount = 0;
gateLoopCountPeopleTimes = 0;
hasPlayedPeopleAnomalyVoice = false; // 重置语音提醒标志
hasShownPeopleAnomalyDialog = false; // 重置弹窗显示标志
// 创建检测任务
dynamicDetectionRunnable = new Runnable() {
@Override
public void run() {
if (!isDynamicPeopleDetectionRunning || currentDetectionCount >= MAX_DETECTION_COUNT) {
stopDynamicPeopleDetection();
return;
}
currentDetectionCount++;
LogManager.logDebug(TAG, "执行动态人数检测,第" + currentDetectionCount + "次");
// 获取门内人数
if (gateABController != null) {
gateABController.get485PeopleNum(new GateABController.PeopleNumCallback() {
@Override
public void onSuccess(int peopleNum) {
LogManager.logDebug(TAG, "检测到门内人数: " + peopleNum);
// 记录检测结果
peopleDetectionResults.add(peopleNum);
//输出peopleDetectionResults
LogManager.logDebug(TAG, "当前人数检测结果列表: " + peopleDetectionResults.toString());
// 如果人数>1,增加计数
if (peopleNum > 1) {
gateLoopCountPeopleTimes++;
LogManager.logWarning(TAG, "检测到人数异常,当前计数: " + gateLoopCountPeopleTimes);
}
// 检查是否门内已清空
if (isGateEmpty(currentDetectionCount, peopleDetectionResults)) {
LogManager.logInfo(TAG, "检测到门内已清空,停止动态检测");
stopDynamicPeopleDetection();
return;
}
// 检查并处理人数异常 - 传入当前检测到的人数
checkPeopleCountAnomaly(peopleNum);
// 计算下次检测间隔
long nextInterval = calculateNextDetectionInterval(currentDetectionCount);
// 安排下次检测
if (isDynamicPeopleDetectionRunning && currentDetectionCount < MAX_DETECTION_COUNT) {
dynamicDetectionHandler.postDelayed(dynamicDetectionRunnable, nextInterval);
} else {
stopDynamicPeopleDetection();
}
}
@Override
public void onError(String errorMessage) {
LogManager.logError(TAG, "获取门内人数失败: " + errorMessage);
// 即使失败也继续检测,但记录0
peopleDetectionResults.add(0);
// 计算下次检测间隔
long nextInterval = calculateNextDetectionInterval(currentDetectionCount);
// 安排下次检测
if (isDynamicPeopleDetectionRunning && currentDetectionCount < MAX_DETECTION_COUNT) {
dynamicDetectionHandler.postDelayed(dynamicDetectionRunnable, nextInterval);
} else {
stopDynamicPeopleDetection();
}
}
});
} else {
LogManager.logError(TAG, "GateABController未初始化,无法进行人数检测");
stopDynamicPeopleDetection();
}
}
};
// 开始第一次检测
dynamicDetectionHandler.post(dynamicDetectionRunnable);
}
/**
* 停止动态人数检测
*/
private void stopDynamicPeopleDetection() {
if (!isDynamicPeopleDetectionRunning) {
return;
}
LogManager.logInfo(TAG, "停止动态人数检测,总检测次数: " + currentDetectionCount + ", 异常计数: " + gateLoopCountPeopleTimes);
isDynamicPeopleDetectionRunning = false;
// 移除待执行的任务
if (dynamicDetectionRunnable != null) {
dynamicDetectionHandler.removeCallbacks(dynamicDetectionRunnable);
}
// 最终检查人数
checkPeopleCountAnomalyFinal(peopleDetectionResults);
}
/**
* 计算下次检测间隔时间(毫秒)
*/
private long calculateNextDetectionInterval(int currentCount) {
long interval;
if (currentCount < 5) {
interval = 50; // 开始阶段:50ms
} else if (currentCount < 10) {
interval = 300; // 5-10次:300ms
} else if (currentCount < 15) {
interval = 600; // 10-15次:600ms
} else if (currentCount < 20) {
interval = 1000; // 15-20次:1000ms
} else if (currentCount < 30) {
interval = 1500; // 20-30次:1500ms
} else {
interval = 1500; // 30次以后:1500ms
}
return interval;
}
/**
* 检查门内是否已清空
*/
private boolean isGateEmpty(int currentIndex, List<Integer> results) {
if (currentIndex >= 3 && results.size() >= 3) {
int recentSum = 0;
int startIndex = Math.max(0, currentIndex - 3);
for (int i = startIndex; i <= currentIndex && i < results.size(); i++) {
recentSum += results.get(i);
}
if (recentSum < 1) {
LogManager.logInfo(TAG, "最近4次检测总人数为0,判断门内已清空");
return true;
}
}
return false;
}
/**
* 检查人数异常并播放语音
*/
private void checkPeopleCountAnomaly(int currentPeopleCount) {
if (currentPeopleCount > 1) {
// 当前检测到人数异常,只在第一次时播放提醒语音和显示弹窗
if (!hasPlayedPeopleAnomalyVoice) {
hasPlayedPeopleAnomalyVoice = true;
hasShownPeopleAnomalyDialog = true;
playVoiceReminder("010"); // 请离场,确认门内外只有1人后再重新进入AB门
showMultiplePeopleDetectedDialog(); // 显示人数异常弹窗
LogManager.logInfo(TAG, "首次检测到人数异常,播放语音提醒并显示弹窗");
// 停止动态检测
stopDynamicPeopleDetection();
} else {
LogManager.logDebug(TAG, "检测到人数异常,但已播放过语音提醒,跳过");
}
}
}
/**
* 最终检查人数异常
*/
private void checkPeopleCountAnomalyFinal(List<Integer> results) {
if (results.isEmpty()) {
return;
}
// 检查是否所有检测结果都小于2
boolean allLessThanTwo = true;
for (int num : results) {
if (num >= 2) {
allLessThanTwo = false;
break;
}
}
if (allLessThanTwo) {
// 重置计数器
gateLoopCountPeopleTimes = 0;
LogManager.logInfo(TAG, "所有检测结果都正常,重置异常计数器");
} else {
// 增加计数器
gateLoopCountPeopleTimes++;
LogManager.logWarning(TAG, "检测到异常人数,最终异常计数: " + gateLoopCountPeopleTimes);
// 如果异常严重,显示弹窗
if (gateLoopCountPeopleTimes >= 3) {
showMultiplePeopleDetectedDialog();
}
}
}
/**
* 显示多人检测弹窗
*/
private void showMultiplePeopleDetectedDialog() {
runOnUiThread(() -> {
try {
if (gateUnavailableDialog != null) {
// 显示进场场景人数异常弹窗,使用当前检测到的人数
int currentPeopleCount = peopleDetectionResults.isEmpty() ? 0 : peopleDetectionResults.get(peopleDetectionResults.size() - 1);
gateUnavailableDialog.updatePeopleCountError(false, currentPeopleCount);
LogManager.logWarning(TAG, "显示多人检测异常弹窗,当前人数: " + currentPeopleCount);
} else {
LogManager.logError(TAG, "GateUnavailableDialog未初始化,无法显示人数异常弹窗");
}
} catch (Exception e) {
LogManager.logError(TAG, "显示多人检测弹窗失败", e);
}
});
}
/**
* 播放语音提醒
*/
private void playVoiceReminder(String voiceType) {
try {
if (voicePlayerManager != null) {
// 根据voiceType字符串找到对应的VoiceType枚举
VoiceType voiceEnum = null;
switch (voiceType) {
case "010":
// 暂时使用ONE_PERSON_ENTRY作为人数异常提醒
voiceEnum = VoiceType.ONE_PERSON_ENTRY;
break;
default:
LogManager.logWarning(TAG, "未知的语音类型: " + voiceType);
return;
}
if (voiceEnum != null) {
voicePlayerManager.playVoice(voiceEnum);
LogManager.logInfo(TAG, "播放语音提醒: " + voiceType + " -> " + voiceEnum.getDescription());
}
} else {
LogManager.logWarning(TAG, "VoicePlayerManager未初始化,无法播放语音");
}
} catch (Exception e) {
LogManager.logError(TAG, "播放语音提醒失败", e);
}
}
/**
* 当门关闭时触发动态人数检测
*/
public void onGateClosed() {
// 如果动态检测已经在运行(通过AB门检查启动的),则不再重复启动
if (isDynamicPeopleDetectionRunning) {
LogManager.logInfo(TAG, "动态人数检测已在运行,跳过门关闭触发");
return;
}
LogManager.logInfo(TAG, "检测到门关闭,开始动态人数检测");
startDynamicPeopleDetection();
}
/**
* 当人脸识别开始时停止动态检测
*/
public void onFaceRecognitionStarted() {
LogManager.logInfo(TAG, "人脸识别开始,停止动态人数检测");
stopDynamicPeopleDetection();
}
/**
* 检查是否需要进行人脸检测
* 当有其他弹窗覆盖在视频流上时,不进行人脸检测
* @return true表示需要检测,false表示不需要检测
*/
private boolean isNeedCheckFace() {
// 1. 当查询到当前GateUnavailableDialog.java已经弹出时,返回false
if (gateUnavailableDialog != null && gateUnavailableDialog.isShowing()) {
return false;
}
// 2. 当查询到当前OrderSelectionActivity.java已经弹出时,返回false
if (isOrderSelectionActivityShowing) {
return false;
}
// 3. 当查询到当前OrderVerificationResultActivity.java已经弹出时,返回false
if (isOrderVerificationResultActivityShowing) {
return false;
}
// 4. 当查询到当前VerificationCodeActivity.java已经弹出时,返回false
if (isVerificationCodeActivityShowing) {
return false;
}
// 5. 当查询到当前UnlockPasswordDialog.java已经弹出时,返回false
if (unlockPasswordDialog != null && unlockPasswordDialog.isShowing()) {
return false;
}
// 其它情况返回true
return true;
}
}