|
|
@ -30,6 +30,9 @@ 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; |
|
|
@ -213,6 +216,18 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
|
// 新增语音播放管理器 |
|
|
|
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; // 订单核销结果页面是否正在显示 |
|
|
@ -451,6 +466,8 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onVerificationSuccess(com.ouxuan.oxface.network.api.PadApiService.CheckOrderResult data, int verificationType) { |
|
|
|
// 人脸识别开始,停止动态人数检测 |
|
|
|
onFaceRecognitionStarted(); |
|
|
|
// 直接处理页面跳转逻辑,不在这里开门 |
|
|
|
orderVerificationResultHandler.handleVerificationSuccess(data, verificationType); |
|
|
|
} |
|
|
@ -923,6 +940,26 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
|
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 |
|
|
@ -1969,6 +2006,14 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
|
return; |
|
|
|
} else { |
|
|
|
LogManager.logInfo(TAG, "AB门人数棈测通过,继续人脸识别流程"); |
|
|
|
|
|
|
|
// AB门检查通过后,开始动态人数检测(防止尾随进入) |
|
|
|
if (checkDynamicPeopleDetectionEnabled()) { |
|
|
|
LogManager.logInfo(TAG, "AB门检查通过,开始动态人数检测"); |
|
|
|
startDynamicPeopleDetection(); |
|
|
|
} else { |
|
|
|
LogManager.logInfo(TAG, "动态人数检测功能未开启"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
@ -3208,4 +3253,304 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
|
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, "首次检测到人数异常,播放语音提醒并显示弹窗"); |
|
|
|
} 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(); |
|
|
|
} |
|
|
|
} |