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.
784 lines
28 KiB
784 lines
28 KiB
package com.ouxuan.oxface.abgate;
|
|
|
|
import android.app.Dialog;
|
|
import android.content.Context;
|
|
import android.graphics.Color;
|
|
import android.graphics.drawable.ColorDrawable;
|
|
import android.os.Handler;
|
|
import android.os.Looper;
|
|
import android.view.Gravity;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.Window;
|
|
import android.view.WindowManager;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.TextView;
|
|
import com.ouxuan.oxface.utils.LogManager;
|
|
import com.ouxuan.oxface.utils.VenueSceneUtils;
|
|
import com.ouxuan.oxface.device.GateABController;
|
|
import com.ouxuan.oxface.device.OxUDP;
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.ScheduledFuture;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
/**
|
|
* 门禁不可用弹窗
|
|
* 当AB门状态异常或门内人数异常时显示
|
|
*
|
|
* @author AI Assistant
|
|
* @version 1.0
|
|
* @date 2024/09/13
|
|
*/
|
|
public class GateUnavailableDialog {
|
|
|
|
private static final String TAG = "GateUnavailableDialog";
|
|
|
|
private Context context;
|
|
private Dialog dialog;
|
|
private TextView tvTitle;
|
|
private TextView tvMessage;
|
|
private TextView tvGateStatus; // 门状态显示
|
|
private TextView tvCountdown; // 倒计时显示(仅离场场景人数异常时使用)
|
|
|
|
// A门开关监听相关
|
|
private boolean isAGateListening = false;
|
|
private boolean lastAGateState = false; // 上一次A门状态
|
|
private AGateStateListener aGateStateListener;
|
|
|
|
// UDP人数轮询相关
|
|
private ScheduledExecutorService udpPollingExecutor;
|
|
private ScheduledFuture<?> udpPollingTask;
|
|
private int udpPollingCount = 0;
|
|
private int consecutiveSuccessCount = 0;
|
|
private static final int UDP_POLLING_MAX_COUNT = 20;
|
|
private static final int UDP_POLLING_INTERVAL_MS = 1500;
|
|
private static final int REQUIRED_SUCCESS_COUNT = 3;
|
|
|
|
// 倒计时相关(离场场景)
|
|
private Handler countdownHandler;
|
|
private Runnable countdownRunnable;
|
|
private int countdownSeconds = 5;
|
|
|
|
// 弹窗类型标识
|
|
private boolean isPeopleCountError = false;
|
|
private boolean isLeaveScene = false;
|
|
|
|
/**
|
|
* A门状态监听器接口
|
|
*/
|
|
public interface AGateStateListener {
|
|
/**
|
|
* A门状态变化监听
|
|
* @param isOpen A门是否开启
|
|
*/
|
|
void onAGateStateChanged(boolean isOpen);
|
|
}
|
|
/**
|
|
* 门禁不可用弹窗操作监听器
|
|
*/
|
|
public interface GateUnavailableDialogListener extends DialogClosedNotifier {
|
|
/**
|
|
* 弹窗显示时触发,需要暂停摄像头和中断其他操作
|
|
*/
|
|
void onDialogShow();
|
|
|
|
/**
|
|
* 弹窗隐藏时触发,可以恢复摄像头和其他操作
|
|
*/
|
|
void onDialogHide();
|
|
|
|
/**
|
|
* 弹窗关闭时触发,用于恢复正常的门禁监控。默认空实现。
|
|
*/
|
|
@Override
|
|
default void onDialogClosed() {
|
|
// 默认空实现,子类可选择实现
|
|
}
|
|
}
|
|
|
|
private GateUnavailableDialogListener dialogListener;
|
|
private boolean isShowing = false;
|
|
|
|
/**
|
|
* 设置弹窗操作监听器
|
|
* @param listener 监听器
|
|
*/
|
|
public void setDialogListener(GateUnavailableDialogListener listener) {
|
|
this.dialogListener = listener;
|
|
}
|
|
|
|
public GateUnavailableDialog(Context context) {
|
|
this.context = context;
|
|
// 初始化线程池和处理器
|
|
udpPollingExecutor = Executors.newSingleThreadScheduledExecutor();
|
|
countdownHandler = new Handler(Looper.getMainLooper());
|
|
createDialog();
|
|
}
|
|
|
|
/**
|
|
* 创建弹窗
|
|
*/
|
|
private void createDialog() {
|
|
dialog = new Dialog(context);
|
|
|
|
// 创建弹窗布局
|
|
LinearLayout mainLayout = new LinearLayout(context);
|
|
mainLayout.setOrientation(LinearLayout.VERTICAL);
|
|
mainLayout.setBackgroundColor(Color.parseColor("#CC000000")); // 半透明黑色背景
|
|
mainLayout.setGravity(Gravity.CENTER);
|
|
mainLayout.setPadding(50, 50, 50, 50);
|
|
|
|
// 内容容器
|
|
LinearLayout contentLayout = new LinearLayout(context);
|
|
contentLayout.setOrientation(LinearLayout.VERTICAL);
|
|
contentLayout.setBackgroundColor(Color.WHITE);
|
|
contentLayout.setPadding(40, 30, 40, 30);
|
|
contentLayout.setGravity(Gravity.CENTER);
|
|
|
|
// 设置圆角效果(通过代码设置)
|
|
android.graphics.drawable.GradientDrawable drawable = new android.graphics.drawable.GradientDrawable();
|
|
drawable.setColor(Color.WHITE);
|
|
drawable.setCornerRadius(20);
|
|
contentLayout.setBackground(drawable);
|
|
|
|
// 标题
|
|
tvTitle = new TextView(context);
|
|
tvTitle.setText("门禁不可用");
|
|
tvTitle.setTextSize(20);
|
|
tvTitle.setTextColor(Color.parseColor("#FF4444"));
|
|
tvTitle.setGravity(Gravity.CENTER);
|
|
tvTitle.setPadding(0, 0, 0, 20);
|
|
|
|
// 消息内容
|
|
tvMessage = new TextView(context);
|
|
tvMessage.setTextSize(16);
|
|
tvMessage.setTextColor(Color.parseColor("#333333"));
|
|
tvMessage.setGravity(Gravity.CENTER);
|
|
tvMessage.setLineSpacing(5, 1.2f);
|
|
|
|
// 门状态显示
|
|
tvGateStatus = new TextView(context);
|
|
tvGateStatus.setTextSize(14);
|
|
tvGateStatus.setTextColor(Color.parseColor("#666666"));
|
|
tvGateStatus.setGravity(Gravity.CENTER);
|
|
tvGateStatus.setPadding(0, 10, 0, 0);
|
|
tvGateStatus.setText("门状态:A门-未知, B门-未知"); // 默认状态
|
|
|
|
// 倒计时显示(仅离场场景人数异常时显示)
|
|
tvCountdown = new TextView(context);
|
|
tvCountdown.setTextSize(16);
|
|
tvCountdown.setTextColor(Color.parseColor("#FF6600"));
|
|
tvCountdown.setGravity(Gravity.CENTER);
|
|
tvCountdown.setPadding(0, 15, 0, 0);
|
|
tvCountdown.setVisibility(View.GONE); // 初始隐藏
|
|
|
|
// 添加视图到容器
|
|
contentLayout.addView(tvTitle);
|
|
contentLayout.addView(tvMessage);
|
|
contentLayout.addView(tvGateStatus); // 添加门状态显示
|
|
contentLayout.addView(tvCountdown); // 添加倒计时显示
|
|
|
|
// 设置内容布局参数
|
|
LinearLayout.LayoutParams contentParams = new LinearLayout.LayoutParams(
|
|
(int)(300 * context.getResources().getDisplayMetrics().density),
|
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
);
|
|
contentParams.gravity = Gravity.CENTER;
|
|
mainLayout.addView(contentLayout, contentParams);
|
|
|
|
// 设置Dialog属性
|
|
dialog.setContentView(mainLayout);
|
|
|
|
Window window = dialog.getWindow();
|
|
if (window != null) {
|
|
// 设置全屏显示
|
|
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
|
|
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
|
|
|
// 设置窗口标志
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
|
|
|
|
// 清除默认动画
|
|
window.setWindowAnimations(0);
|
|
}
|
|
|
|
// 设置不可取消
|
|
dialog.setCancelable(false);
|
|
dialog.setCanceledOnTouchOutside(false);
|
|
}
|
|
|
|
/**
|
|
* 更新门状态显示
|
|
* @param gateAOpen A门是否开启
|
|
* @param gateBOpen B门是否开启
|
|
* @param udpConnected UDP连接状态
|
|
*/
|
|
private void updateGateStatusDisplay(boolean gateAOpen, boolean gateBOpen, boolean udpConnected) {
|
|
String gateAStatus = gateAOpen ? "开启" : "关闭";
|
|
String gateBStatus = gateBOpen ? "开启" : "关闭";
|
|
String udpStatus = udpConnected ? "正常" : "异常";
|
|
|
|
String statusText = "门状态:A门-" + gateAStatus + ", B门-" + gateBStatus + " | UDP-" + udpStatus;
|
|
tvGateStatus.setText(statusText);
|
|
|
|
LogManager.logInfo(TAG, "更新门状态显示: " + statusText);
|
|
}
|
|
|
|
/**
|
|
* 更新门状态异常弹窗内容(带门状态信息)
|
|
* @param reason 新的不可用原因
|
|
* @param gateAOpen A门是否开启
|
|
* @param gateBOpen B门是否开启
|
|
* @param udpConnected UDP连接状态
|
|
*/
|
|
public void updateGateStateError(String reason, boolean gateAOpen, boolean gateBOpen, boolean udpConnected) {
|
|
LogManager.logInfo(TAG, "更新门状态异常弹窗内容: " + reason +
|
|
", A门: " + (gateAOpen ? "开启" : "关闭") +
|
|
", B门: " + (gateBOpen ? "开启" : "关闭") +
|
|
", UDP: " + (udpConnected ? "正常" : "异常"));
|
|
|
|
tvTitle.setText("门禁不可用");
|
|
tvMessage.setText(reason);
|
|
|
|
// 更新门状态显示
|
|
updateGateStatusDisplay(gateAOpen, gateBOpen, udpConnected);
|
|
|
|
// 如果弹窗未显示,则显示弹窗
|
|
if (!isShowing) {
|
|
show();
|
|
} else {
|
|
LogManager.logInfo(TAG, "弹窗已显示,仅更新内容");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新门状态异常弹窗内容(简化版,不显示门状态)
|
|
* @param reason 新的不可用原因
|
|
*/
|
|
public void updateGateStateError(String reason) {
|
|
LogManager.logInfo(TAG, "更新门状态异常弹窗内容: " + reason);
|
|
|
|
tvTitle.setText("门禁不可用");
|
|
tvMessage.setText(reason);
|
|
|
|
// 不更新门状态显示,保持之前的状态
|
|
|
|
// 如果弹窗未显示,则显示弹窗
|
|
if (!isShowing) {
|
|
show();
|
|
} else {
|
|
LogManager.logInfo(TAG, "弹窗已显示,仅更新内容");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新人数异常弹窗内容
|
|
* @param isLeaveScene 是否为离场场景
|
|
* @param peopleCount 门内人数
|
|
*/
|
|
public void updatePeopleCountError(boolean isLeaveScene, int peopleCount) {
|
|
String message;
|
|
|
|
// 记录弹窗类型和场景
|
|
this.isPeopleCountError = true;
|
|
this.isLeaveScene = isLeaveScene;
|
|
|
|
if (isLeaveScene) {
|
|
// 离场场景:检测到门内有人
|
|
message = "AB门离场:检测到门内有 " + peopleCount + " 人\n请等待门禁内人员离开后操作";
|
|
LogManager.logInfo(TAG, "更新离场人数异常弹窗内容,门内人数: " + peopleCount);
|
|
} else {
|
|
// 进场场景:检测到门内人数大于1
|
|
message = "AB门进场:检测到门内有 " + peopleCount + " 人\n请一次一人进场,确保门禁内只有一人时操作";
|
|
LogManager.logInfo(TAG, "更新进场人数异常弹窗内容,门内人数: " + peopleCount);
|
|
}
|
|
|
|
tvTitle.setText("门禁不可用");
|
|
tvMessage.setText(message);
|
|
|
|
// 不更新门状态显示,保持之前的状态
|
|
|
|
// 如果弹窗未显示,则显示弹窗
|
|
if (!isShowing) {
|
|
show();
|
|
|
|
// 根据场景类型应用不同的关闭条件
|
|
applySceneSpecificClosingConditions();
|
|
} else {
|
|
LogManager.logInfo(TAG, "弹窗已显示,仅更新内容");
|
|
// 如果已经显示,重新应用关闭条件
|
|
applySceneSpecificClosingConditions();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 根据场景类型应用相应的关闭条件
|
|
*/
|
|
private void applySceneSpecificClosingConditions() {
|
|
if (!isPeopleCountError) {
|
|
LogManager.logInfo(TAG, "非人数异常弹窗,不应用特殊关闭条件");
|
|
return;
|
|
}
|
|
|
|
// 先停止之前的所有监听
|
|
stopAllMonitoring();
|
|
|
|
if (isLeaveScene) {
|
|
// 离场场景:启动倒计时自动关闭
|
|
LogManager.logInfo(TAG, "离场场景人数异常,启动倒计时自动关闭");
|
|
startLeaveSceneCountdown();
|
|
} else {
|
|
// 进场场景:启动A门开关监听
|
|
LogManager.logInfo(TAG, "进场场景人数异常,启动A门开关监听");
|
|
startAGateOpenCloseMonitoring();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 停止所有监听(不关闭弹窗)
|
|
*/
|
|
private void stopAllMonitoring() {
|
|
// 停止A门监听
|
|
if (isAGateListening) {
|
|
isAGateListening = false;
|
|
aGateStateListener = null;
|
|
LogManager.logInfo(TAG, "停止A门监听");
|
|
}
|
|
|
|
// 停止UDP轮询
|
|
stopUdpLoopCheckNum();
|
|
|
|
// 停止倒计时
|
|
stopCountdown();
|
|
}
|
|
|
|
/**
|
|
* 显示弹窗
|
|
*/
|
|
private void show() {
|
|
try {
|
|
if (dialog != null && !isShowing) {
|
|
dialog.show();
|
|
isShowing = true;
|
|
LogManager.logInfo(TAG, "门禁不可用弹窗已显示");
|
|
|
|
// 通知监听器弹窗显示,需要暂停摄像头和中断操作
|
|
if (dialogListener != null) {
|
|
dialogListener.onDialogShow();
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
LogManager.logError(TAG, "显示弹窗失败", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 开始A门开关监听(仅进场场景人数异常时使用)
|
|
*/
|
|
private void startAGateOpenCloseMonitoring() {
|
|
LogManager.logInfo(TAG, "开始A门开关监听");
|
|
|
|
if (isAGateListening) {
|
|
LogManager.logInfo(TAG, "A门监听器已在运行,重置状态");
|
|
// 重置状态
|
|
stopUdpLoopCheckNum();
|
|
}
|
|
|
|
isAGateListening = true;
|
|
|
|
// 创建A门状态监听器
|
|
aGateStateListener = new AGateStateListener() {
|
|
@Override
|
|
public void onAGateStateChanged(boolean isOpen) {
|
|
LogManager.logInfo(TAG, "A门状态变化: " + (isOpen ? "开启" : "关闭"));
|
|
|
|
// 检测A门由开启变为关闭
|
|
if (lastAGateState && !isOpen) {
|
|
LogManager.logInfo(TAG, "检测到A门由开启变为关闭,触发UDP轮询人数检测");
|
|
// 重置之前的UDP轮询(如果正在运行)
|
|
stopUdpLoopCheckNum();
|
|
// 启动新的UDP轮询
|
|
startUdpLoopCheckNum();
|
|
}
|
|
|
|
lastAGateState = isOpen;
|
|
}
|
|
};
|
|
|
|
// 将监听器注册到OxUDP或GateABController中
|
|
registerAGateStateListener();
|
|
}
|
|
|
|
/**
|
|
* 注册到UDP监听器中获取A门状态变化
|
|
*/
|
|
private void registerAGateStateListener() {
|
|
try {
|
|
OxUDP.getInstance().setStateListener(new OxUDP.UDPStateListener() {
|
|
@Override
|
|
public void onGateStateUpdate(boolean gateAState, boolean gateBState, String rawData) {
|
|
if (aGateStateListener != null) {
|
|
aGateStateListener.onAGateStateChanged(gateAState);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onGateOpenResult(String gateType, boolean success) {
|
|
// 不处理开门结果
|
|
}
|
|
|
|
@Override
|
|
public void onUDPError(String error) {
|
|
LogManager.logError(TAG, "UDP错误: " + error);
|
|
}
|
|
});
|
|
} catch (Exception e) {
|
|
LogManager.logError(TAG, "注册A门监听器失败", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 停止A门开关监听
|
|
*/
|
|
private void stopAGateOpenCloseMonitoring() {
|
|
LogManager.logInfo(TAG, "停止A门开关监听");
|
|
isAGateListening = false;
|
|
aGateStateListener = null;
|
|
|
|
// 同时停止UDP轮询
|
|
stopUdpLoopCheckNum();
|
|
|
|
// 清空状态
|
|
lastAGateState = false;
|
|
}
|
|
|
|
/**
|
|
* 启动UDP轮询人数检测(20次,每1.5秒一次)
|
|
*/
|
|
private void startUdpLoopCheckNum() {
|
|
LogManager.logInfo(TAG, "启动UDP轮询人数检测");
|
|
|
|
// 重置计数器
|
|
udpPollingCount = 0;
|
|
consecutiveSuccessCount = 0;
|
|
|
|
udpPollingTask = udpPollingExecutor.scheduleAtFixedRate(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
udpPollingCount++;
|
|
LogManager.logInfo(TAG, "UDP轮询人数检测第 " + udpPollingCount + " 次");
|
|
|
|
try {
|
|
// 获取485人数
|
|
GateABController.getInstance().get485PeopleNum(new GateABController.PeopleNumCallback() {
|
|
@Override
|
|
public void onSuccess(int peopleNum) {
|
|
LogManager.logInfo(TAG, "UDP轮询第" + udpPollingCount + "次,检测人数: " + peopleNum);
|
|
|
|
// 检查A、B门是否都关闭
|
|
checkGatesAndPeopleCount(peopleNum);
|
|
}
|
|
|
|
@Override
|
|
public void onError(String errorMessage) {
|
|
LogManager.logError(TAG, "UDP轮询第" + udpPollingCount + "次人数获取失败: " + errorMessage);
|
|
|
|
// 错误时也要检查是否达到最大次数
|
|
checkMaxPollingCount();
|
|
}
|
|
});
|
|
|
|
} catch (Exception e) {
|
|
LogManager.logError(TAG, "UDP轮询检测异常", e);
|
|
checkMaxPollingCount();
|
|
}
|
|
}
|
|
}, 0, UDP_POLLING_INTERVAL_MS, TimeUnit.MILLISECONDS);
|
|
}
|
|
|
|
/**
|
|
* 检查门状态和人数
|
|
* @param peopleNum 人数
|
|
*/
|
|
private void checkGatesAndPeopleCount(int peopleNum) {
|
|
try {
|
|
LogManager.logInfo(TAG, "UDP轮询检查开始 - 人数: " + peopleNum);
|
|
|
|
// 直接使用当前已知的门状态,避免主动查询UDP
|
|
// 假设当AB门都关闭时才会进入这个检查流程(根据需求描述)
|
|
boolean gatesAllClosed = true; // 在这个上下文中,假设门都已关闭
|
|
|
|
LogManager.logInfo(TAG, "UDP轮询检查结果 - 门状态: " + (gatesAllClosed ? "AB门均关闭" : "有门开启") + ", 人数: " + peopleNum);
|
|
|
|
if (gatesAllClosed && peopleNum == 1) {
|
|
consecutiveSuccessCount++;
|
|
LogManager.logInfo(TAG, "满足条件的连续次数: " + consecutiveSuccessCount + "/" + REQUIRED_SUCCESS_COUNT);
|
|
|
|
if (consecutiveSuccessCount >= REQUIRED_SUCCESS_COUNT) {
|
|
LogManager.logInfo(TAG, "连续" + REQUIRED_SUCCESS_COUNT + "次检测到门内人数为1人且AB门均关闭,关闭弹窗");
|
|
// 关闭弹窗并停止监听
|
|
closeDialogAndStopMonitoring();
|
|
return;
|
|
}
|
|
} else {
|
|
// 不满足条件,重置连续次数
|
|
consecutiveSuccessCount = 0;
|
|
}
|
|
|
|
// 检查是否达到最大轮询次数
|
|
checkMaxPollingCount();
|
|
|
|
} catch (Exception e) {
|
|
LogManager.logError(TAG, "检查门状态和人数异常", e);
|
|
// 错误时重置连续次数
|
|
consecutiveSuccessCount = 0;
|
|
// 检查是否达到最大轮询次数
|
|
checkMaxPollingCount();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查是否达到最大轮询次数
|
|
*/
|
|
private void checkMaxPollingCount() {
|
|
if (udpPollingCount >= UDP_POLLING_MAX_COUNT) {
|
|
LogManager.logInfo(TAG, "达到" + UDP_POLLING_MAX_COUNT + "次轮询上限,自动结束并关闭弹窗");
|
|
closeDialogAndStopMonitoring();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 停止UDP轮询人数检测
|
|
*/
|
|
private void stopUdpLoopCheckNum() {
|
|
if (udpPollingTask != null && !udpPollingTask.isCancelled()) {
|
|
udpPollingTask.cancel(true);
|
|
udpPollingTask = null;
|
|
LogManager.logInfo(TAG, "UDP轮询人数检测已停止");
|
|
}
|
|
|
|
// 重置计数器
|
|
udpPollingCount = 0;
|
|
consecutiveSuccessCount = 0;
|
|
}
|
|
|
|
/**
|
|
* 关闭弹窗并停止所有监听
|
|
*/
|
|
private void closeDialogAndStopMonitoring() {
|
|
// 停止A门监听
|
|
stopAGateOpenCloseMonitoring();
|
|
|
|
// 停止倒计时(如果正在运行)
|
|
stopCountdown();
|
|
|
|
// 关闭弹窗
|
|
hide();
|
|
}
|
|
|
|
/**
|
|
* 启动离场场景的倒计时自动关闭(5秒)
|
|
*/
|
|
private void startLeaveSceneCountdown() {
|
|
LogManager.logInfo(TAG, "启动离场场景5秒倒计时");
|
|
|
|
// 显示倒计时文本
|
|
tvCountdown.setVisibility(View.VISIBLE);
|
|
|
|
// 重置倒计时
|
|
countdownSeconds = 5;
|
|
|
|
// 更新倒计时显示
|
|
updateCountdownDisplay();
|
|
|
|
// 创建倒计时任务
|
|
countdownRunnable = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
countdownSeconds--;
|
|
|
|
if (countdownSeconds > 0) {
|
|
// 更新显示并继续倒计时
|
|
updateCountdownDisplay();
|
|
countdownHandler.postDelayed(this, 1000);
|
|
} else {
|
|
// 倒计时结束,自动关闭弹窗
|
|
LogManager.logInfo(TAG, "离场场景5秒倒计时结束,自动关闭弹窗");
|
|
closeDialogAndStopMonitoring();
|
|
}
|
|
}
|
|
};
|
|
|
|
// 延迟1秒开始倒计时
|
|
countdownHandler.postDelayed(countdownRunnable, 1000);
|
|
}
|
|
|
|
/**
|
|
* 更新倒计时显示
|
|
*/
|
|
private void updateCountdownDisplay() {
|
|
if (tvCountdown != null) {
|
|
tvCountdown.setText("将在 " + countdownSeconds + " 秒后自动关闭");
|
|
LogManager.logInfo(TAG, "更新倒计时显示: " + countdownSeconds + "秒");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 停止倒计时
|
|
*/
|
|
private void stopCountdown() {
|
|
if (countdownHandler != null && countdownRunnable != null) {
|
|
countdownHandler.removeCallbacks(countdownRunnable);
|
|
countdownRunnable = null;
|
|
LogManager.logInfo(TAG, "倒计时已停止");
|
|
}
|
|
|
|
// 隐藏倒计时显示
|
|
if (tvCountdown != null) {
|
|
tvCountdown.setVisibility(View.GONE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 隐藏弹窗
|
|
*/
|
|
public void hide() {
|
|
try {
|
|
// 停止所有监听
|
|
stopAllMonitoring();
|
|
|
|
// 重置弹窗类型标识(仅在非人数异常弹窗时重置)
|
|
// 注意:不在这里重置 isPeopleCountError,保持状态以便正确区分弹窗类型
|
|
LogManager.logInfo(TAG, "隐藏弹窗,弹窗类型: " + (isPeopleCountError ? "人数异常" : "门状态异常"));
|
|
|
|
if (dialog != null && isShowing) {
|
|
dialog.dismiss();
|
|
isShowing = false;
|
|
LogManager.logInfo(TAG, "门禁不可用弹窗已隐藏");
|
|
|
|
// 通知监听器弹窗隐藏,可以恢复摄像头和操作
|
|
if (dialogListener != null) {
|
|
dialogListener.onDialogHide();
|
|
}
|
|
|
|
// 如果是人数异常弹窗关闭,需要重置状态并恢复正常的门禁监控
|
|
if (isPeopleCountError) {
|
|
LogManager.logInfo(TAG, "人数异常弹窗关闭,重置状态并恢复正常门禁监控");
|
|
// 重置人数异常标识
|
|
isPeopleCountError = false;
|
|
isLeaveScene = false;
|
|
|
|
// 通知系统恢复正常的门禁监控状态
|
|
notifyDialogClosed();
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
LogManager.logError(TAG, "隐藏弹窗失败", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 通知弹窗关闭,用于恢复正常的门禁监控
|
|
*/
|
|
private void notifyDialogClosed() {
|
|
try {
|
|
// 通过监听器通知系统弹窗已关闭,可以恢复正常门禁监控
|
|
if (dialogListener instanceof DialogClosedNotifier) {
|
|
((DialogClosedNotifier) dialogListener).onDialogClosed();
|
|
}
|
|
LogManager.logInfo(TAG, "已通知系统恢复正常门禁监控");
|
|
} catch (Exception e) {
|
|
LogManager.logError(TAG, "通知弹窗关闭失败", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 弹窗关闭通知接口(可选实现)
|
|
*/
|
|
public interface DialogClosedNotifier {
|
|
/**
|
|
* 弹窗关闭时触发,用于恢复正常的门禁监控
|
|
*/
|
|
void onDialogClosed();
|
|
}
|
|
|
|
/**
|
|
* 检查是否应该显示弹窗
|
|
* 根据业务规则进行判断:
|
|
* - 对于离场设备,检测到网络中断后不显示弹窗(不阻碍离场断网直接开门功能)
|
|
* - 对于进场设备,始终显示弹窗
|
|
*
|
|
* @param context 上下文
|
|
* @param isNetworkAvailable 网络是否可用
|
|
* @return true表示应该显示弹窗
|
|
*/
|
|
public boolean checkShow(Context context, boolean isNetworkAvailable) {
|
|
try {
|
|
// 先检测设备场景
|
|
boolean isLeaveScene = com.ouxuan.oxface.utils.VenueSceneUtils.isLeaveScene(context);
|
|
|
|
if (isLeaveScene) {
|
|
// 离场设备:检测到网络中断后,弹窗不显示(不阻碍离场断网直接开门功能)
|
|
if (!isNetworkAvailable) {
|
|
LogManager.logInfo(TAG, "离场设备检测到网络中断,不显示门禁不可用弹窗(保持离场断网直接开门功能)");
|
|
return false;
|
|
}
|
|
// 离场设备且网络可用,显示弹窗
|
|
LogManager.logInfo(TAG, "离场设备且网络可用,可以显示门禁不可用弹窗");
|
|
return true;
|
|
} else {
|
|
// 进场设备:始终显示弹窗
|
|
LogManager.logInfo(TAG, "进场设备,可以显示门禁不可用弹窗");
|
|
return true;
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
LogManager.logError(TAG, "检查是否显示弹窗时发生异常,默认显示", e);
|
|
return true; // 异常情况下默认显示弹窗
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查弹窗是否正在显示
|
|
* @return true表示正在显示
|
|
*/
|
|
public boolean isShowing() {
|
|
return isShowing;
|
|
}
|
|
|
|
/**
|
|
* 释放资源
|
|
*/
|
|
public void release() {
|
|
// 停止所有监听
|
|
stopAllMonitoring();
|
|
|
|
// 关闭弹窗
|
|
hide();
|
|
|
|
// 释放线程资源
|
|
if (udpPollingExecutor != null && !udpPollingExecutor.isShutdown()) {
|
|
udpPollingExecutor.shutdown();
|
|
udpPollingExecutor = null;
|
|
}
|
|
|
|
// 清空处理器
|
|
if (countdownHandler != null) {
|
|
countdownHandler.removeCallbacksAndMessages(null);
|
|
countdownHandler = null;
|
|
}
|
|
|
|
// 清空引用
|
|
if (dialog != null) {
|
|
dialog = null;
|
|
}
|
|
context = null;
|
|
dialogListener = null;
|
|
aGateStateListener = null;
|
|
|
|
LogManager.logInfo(TAG, "门禁不可用弹窗资源已释放");
|
|
}
|
|
}
|