Browse Source

add udp init & use in face detect

dev
赵明涛 3 days ago
parent
commit
2be0b17bb6
  1. 144
      UDP门禁控制系统集成完成说明.md
  2. 85
      app/src/main/java/com/ouxuan/oxface/OXFaceOnlineActivity.java
  3. 599
      app/src/main/java/com/ouxuan/oxface/device/OxUDP.java
  4. 296
      app/src/main/java/com/ouxuan/oxface/device/OxUDPUsageExample.java

144
UDP门禁控制系统集成完成说明.md

@ -0,0 +1,144 @@
# OxUDP门禁控制系统集成完成说明
## 完成的功能
### 1. 核心UDP门禁控制类
- **OxUDP.java**: 基于原生UDP Socket实现的门禁控制核心类
- 支持设备信息查询和更新(`initUDP`函数)
- 支持门禁状态轮询(每秒查询一次)
- 支持A门(进门)和B门(出门)开启控制
- 支持门关闭时间设置
- 完整的错误处理和重连机制
### 2. 使用示例和集成类
- **OxUDPUsageExample.java**: 详细的使用示例和集成指导
- **UDPTestActivity.java**: 独立的UDP功能测试界面
### 3. 人脸识别界面集成
已成功将UDP门禁控制集成到 **OXFaceOnlineActivity.java** 中:
#### 初始化部分
- 在 `onCreate()` 方法中添加UDP初始化
- 在 `onResume()` 中启动门禁状态轮询
- 在 `onPause()` 中停止轮询
- 在 `onDestroy()` 中清理资源
#### 人脸识别成功处理
`checkResultOnline()` 方法中,人脸识别成功后:
- **进场场景**:开启A门(进门)
- **离场场景**:开启B门(出门)
- 支持网络异常时仅开启门禁(不进行网络校验)
## UDP配置参数
根据您提供的参数,系统已配置:
```java
// UDP连接配置
private static final String UDP_IP = "192.168.1.123"; // MJ AB中控
private static final int UDP_SEND_PORT = 60000; // 发送端口
// 门禁命令配置
private String udp_device_cmd = "17 94 00 00 ..."; // 设备查询命令
private String udp_state_cmd = "17 20 00 00 ..."; // 状态查询命令
private String udp_open_a_cmd = "17 40 00 00 ..."; // A门开启命令
private String udp_open_b_cmd = "17 40 00 00 ..."; // B门开启命令
private String udp_gate_a_close_time_cmd = "17 80 00 00 ..."; // A门时间设置命令
```
## 工作流程
### 1. 初始化阶段
1. 应用启动时初始化UDP连接
2. 发送设备查询命令获取设备信息
3. 使用返回的设备信息更新所有命令的4-7位参数
4. 开始门禁状态轮询(每1秒一次)
### 2. 人脸识别阶段
1. 用户在人脸识别界面前站立
2. 系统持续进行人脸检测和活体检测
3. 人脸识别成功后获取base64图像数据
### 3. 门禁控制阶段
根据场景自动判断:
- **进场场景**
- 执行订单核销网络请求(如果网络可用)
- 发送A门开启命令(进门)
- 记录日志:"进场场景人脸识别成功,开启A门(进门)"
- **离场场景**
- 执行离场校验网络请求(如果网络可用)
- 发送B门开启命令(出门)
- 记录日志:"离场场景人脸识别成功,开启B门(出门)"
### 4. 状态监控
- 实时监控门禁状态(开启/关闭)
- 监控UDP通信状态
- 自动处理网络异常和重连
## 关键特性
### 1. 智能场景判断
- 使用 `VenueSceneUtils.isLeaveScene()` 判断进场/离场
- 自动选择对应的门禁操作
### 2. 网络异常处理
- 网络可用:执行完整的网络校验 + 门禁开启
- 网络异常:仅执行门禁开启,确保用户可以通行
### 3. 完整的日志记录
- 每个关键操作都有详细日志
- 便于后续问题排查和系统维护
### 4. 资源管理
- 自动管理UDP连接和轮询任务
- 在Activity生命周期中正确启动和停止服务
## 测试建议
### 1. 独立UDP测试
可以使用 `UDPTestActivity` 进行独立的UDP功能测试:
1. 在AndroidManifest.xml中注册Activity
2. 启动测试界面
3. 测试客户端连接、消息发送等功能
### 2. 集成测试
1. 确保设备与UDP服务器(192.168.1.123:60000)网络连通
2. 启动人脸识别界面
3. 观察日志中的UDP初始化和轮询信息
4. 进行人脸识别测试,观察门禁开启效果
### 3. 网络异常测试
1. 断开网络连接
2. 进行人脸识别
3. 验证门禁是否仍能正常开启
## 日志关键词
在logcat中可以搜索以下关键词查看UDP相关日志:
- `OxUDP`: UDP核心功能日志
- `UDPManagerExample`: UDP使用示例日志
- `OXFaceOnlineActivity`: 人脸识别界面集成日志
- `UDP门禁控制`: 门禁控制相关日志
- `进场场景人脸识别成功`: 进门开启A门
- `离场场景人脸识别成功`: 出门开启B门
## 配置调整
如需调整配置,可修改以下文件:
- **UDP连接参数**:`OxUDP.java` 中的常量定义
- **轮询频率**:`POLLING_INTERVAL` 常量(默认1000ms)
- **超时时间**:`UDP_TIMEOUT` 常量(默认3000ms)
- **门关闭时间**:`udp_gate_a_close_time` 变量(默认2秒)
## 总结
UDP门禁控制系统已完全集成到现有的人脸识别项目中,实现了:
1. ✅ 设备信息自动查询和命令更新
2. ✅ 实时门禁状态轮询
3. ✅ 人脸识别成功后自动开门
4. ✅ 智能场景判断(进门/出门)
5. ✅ 网络异常时的容错处理
6. ✅ 完整的资源管理和错误处理
系统现在可以在用户进入人脸识别界面后自动连接UDP服务器,持续轮询门禁状态,并在人脸识别成功后自动执行相应的开门操作。

85
app/src/main/java/com/ouxuan/oxface/OXFaceOnlineActivity.java

@ -51,6 +51,8 @@ import com.ouxuan.oxface.network.OrderVerificationResultHandler;
import com.ouxuan.oxface.network.LeaveVerificationManager; import com.ouxuan.oxface.network.LeaveVerificationManager;
import com.ouxuan.oxface.utils.VenueSceneUtils; import com.ouxuan.oxface.utils.VenueSceneUtils;
import com.ouxuan.oxface.network.NetworkStatusIndicator; import com.ouxuan.oxface.network.NetworkStatusIndicator;
import com.ouxuan.oxface.device.OxUDP;
import com.ouxuan.oxface.device.OxUDPUsageExample;
import java.util.List; import java.util.List;
@ -188,6 +190,10 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
// 网络状态指示器 // 网络状态指示器
private NetworkStatusIndicator networkStatusIndicator; private NetworkStatusIndicator networkStatusIndicator;
// UDP门禁控制
private OxUDPUsageExample udpExample;
private boolean isUDPInitialized = false;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -209,8 +215,11 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
initView(); initView();
// 初始化并注册广播接收器
initCameraControlReceiver();
// 初始化UDP门禁控制
initializeUDPGateControl();
// 初始化网络状态指示器
initNetworkStatusIndicator();
// 初始化人脸检测状态 // 初始化人脸检测状态
lastFaceDetectedTime = System.currentTimeMillis(); lastFaceDetectedTime = System.currentTimeMillis();
@ -229,9 +238,6 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
// 启动内存优化周期性任务 // 启动内存优化周期性任务
startMemoryOptimizationTask(); startMemoryOptimizationTask();
// 初始化网络状态指示器
initNetworkStatusIndicator();
// 更新小程序码 // 更新小程序码
android.util.Log.d(TAG, "准备调用updateMiniQrcode方法"); android.util.Log.d(TAG, "准备调用updateMiniQrcode方法");
@ -505,9 +511,6 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
// 初始化测试弹窗 // 初始化测试弹窗
initTestPopWindow(); initTestPopWindow();
// 初始化网络状态指示器
initNetworkStatusIndicator();
android.util.Log.d(TAG, "初始化界面视图结束"); android.util.Log.d(TAG, "初始化界面视图结束");
} }
@ -585,6 +588,28 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
} }
/** /**
* 初始化UDP门禁控制
*/
private void initializeUDPGateControl() {
try {
LogManager.logInfo(TAG, "开始初始化UDP门禁控制");
// 初始化UDP使用示例类
udpExample = new OxUDPUsageExample(this);
// 初始化UDP门禁功能
udpExample.initializeInFaceActivity();
isUDPInitialized = true;
LogManager.logInfo(TAG, "UDP门禁控制初始化成功");
} catch (Exception e) {
LogManager.logError(TAG, "UDP门禁控制初始化失败", e);
isUDPInitialized = false;
}
}
/**
* 初始化网络状态指示器 * 初始化网络状态指示器
*/ */
private void initNetworkStatusIndicator() { private void initNetworkStatusIndicator() {
@ -624,6 +649,12 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
networkStatusIndicator.startMonitoring(); networkStatusIndicator.startMonitoring();
} }
// 启动UDP门禁状态轮询
if (isUDPInitialized && udpExample != null) {
udpExample.startGatePolling();
LogManager.logInfo(TAG, "UDP门禁状态轮询已启动");
}
// 只有在拥有相机权限时才启动预览 // 只有在拥有相机权限时才启动预览
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) { == PackageManager.PERMISSION_GRANTED) {
@ -1142,6 +1173,14 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
networkStatusIndicator = null; networkStatusIndicator = null;
} }
// 清理UDP门禁控制资源
if (udpExample != null) {
udpExample.cleanup();
udpExample = null;
LogManager.logInfo(TAG, "UDP门禁控制资源已清理");
}
isUDPInitialized = false;
// 注销广播接收器 // 注销广播接收器
if (cameraControlReceiver != null) { if (cameraControlReceiver != null) {
unregisterReceiver(cameraControlReceiver); unregisterReceiver(cameraControlReceiver);
@ -1189,6 +1228,12 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
networkStatusIndicator.stopMonitoring(); networkStatusIndicator.stopMonitoring();
} }
// 停止UDP门禁状态轮询
if (isUDPInitialized && udpExample != null) {
udpExample.stopGatePolling();
LogManager.logInfo(TAG, "UDP门禁状态轮询已停止");
}
LogManager.logInfo(TAG, "OXFaceOnlineActivity onStop - 应用进入后台"); LogManager.logInfo(TAG, "OXFaceOnlineActivity onStop - 应用进入后台");
// 应用进入后台时进一步降低处理频率以节省资源 // 应用进入后台时进一步降低处理频率以节省资源
@ -1326,6 +1371,12 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
if (isNetworkAvailable()) { if (isNetworkAvailable()) {
LogManager.logInfo(TAG, "检测到离场场景,网络可用,执行离场校验"); LogManager.logInfo(TAG, "检测到离场场景,网络可用,执行离场校验");
performLeaveVerification(base64img); performLeaveVerification(base64img);
// 离场场景开启B门出门
if (isUDPInitialized && udpExample != null) {
LogManager.logInfo(TAG, "离场场景人脸识别成功,开启B门(出门)");
udpExample.handleFaceRecognitionSuccess(false); // false表示出门
}
} else { } else {
LogManager.logWarning(TAG, "检测到离场场景,但网络不可用,跳过离场校验"); LogManager.logWarning(TAG, "检测到离场场景,但网络不可用,跳过离场校验");
showLoadingStatus("无网络..."); showLoadingStatus("无网络...");
@ -1336,12 +1387,24 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
hideLoadingStatus(); hideLoadingStatus();
} }
}, 3000); }, 3000);
// 网络不可用时仅开启门禁不进行网络校验
if (isUDPInitialized && udpExample != null) {
LogManager.logInfo(TAG, "离场场景网络不可用,直接开启B门(出门)");
udpExample.handleFaceRecognitionSuccess(false); // false表示出门
}
} }
} else { } else {
// 进场场景先检查网络状态 // 进场场景先检查网络状态
if (isNetworkAvailable()) { if (isNetworkAvailable()) {
LogManager.logInfo(TAG, "检测到进场场景,网络可用,执行订单核销"); LogManager.logInfo(TAG, "检测到进场场景,网络可用,执行订单核销");
getCheckOrder(); getCheckOrder();
// 进场场景开启A门进门
if (isUDPInitialized && udpExample != null) {
LogManager.logInfo(TAG, "进场场景人脸识别成功,开启A门(进门)");
udpExample.handleFaceRecognitionSuccess(true); // true表示进门
}
} else { } else {
LogManager.logWarning(TAG, "检测到进场场景,但网络不可用,跳过订单核销"); LogManager.logWarning(TAG, "检测到进场场景,但网络不可用,跳过订单核销");
showLoadingStatus("无网络..."); showLoadingStatus("无网络...");
@ -1352,6 +1415,12 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi
hideLoadingStatus(); hideLoadingStatus();
} }
}, 3000); }, 3000);
// 网络不可用时仅开启门禁不进行网络校验
if (isUDPInitialized && udpExample != null) {
LogManager.logInfo(TAG, "进场场景网络不可用,直接开启A门(进门)");
udpExample.handleFaceRecognitionSuccess(true); // true表示进门
}
} }
} }

599
app/src/main/java/com/ouxuan/oxface/device/OxUDP.java

@ -0,0 +1,599 @@
package com.ouxuan.oxface.device;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* 门禁UDP通信控制类
* 用于控制AB门的开关状态查询和操作
*
* 功能特性
* - 支持设备信息查询和更新
* - 支持门禁状态轮询
* - 支持A门B门开门控制
* - 支持门关闭时间设置
*
* @author AI Assistant
* @version 1.0
*/
public class OxUDP {
private static final String TAG = "OxUDP";
// UDP配置参数
private static final String UDP_IP = "192.168.1.123"; // MJ AB中控-所有设备通用
private static final int UDP_SEND_PORT = 60000; // 发送端口
private static final int POLLING_INTERVAL = 1000; // 轮询间隔毫秒
private static final int UDP_TIMEOUT = 3000; // UDP超时时间毫秒
// UDP命令定义
private String udp_device_cmd = "17 94 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
private String udp_state_cmd = "17 20 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
private String udp_open_a_cmd = "17 40 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
private String udp_open_b_cmd = "17 40 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
private String udp_gate_a_close_time_cmd = "17 80 00 00 3E 4F 18 0F 01 03 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
// 状态变量
private String udp_device_res = ""; // 设备返回的数据
private int udp_gate_a_close_time = 2; // A门关闭时间
private boolean isInitialized = false;
private boolean isPolling = false;
// 线程管理
private ExecutorService executorService;
private ScheduledExecutorService scheduledExecutor;
private ScheduledFuture<?> pollingTask;
private Handler mainHandler;
// 单例实例
private static OxUDP instance;
private Context context;
// 回调接口
private UDPStateListener stateListener;
private UDPDeviceListener deviceListener;
/**
* UDP状态监听接口
*/
public interface UDPStateListener {
/**
* 门禁状态更新
* @param gateAState A门状态 (true: 开启, false: 关闭)
* @param gateBState B门状态 (true: 开启, false: 关闭)
* @param rawData 原始返回数据
*/
void onGateStateUpdate(boolean gateAState, boolean gateBState, String rawData);
/**
* 门开启成功回调
* @param gateType 门类型 ("A" "B")
* @param success 是否成功
*/
void onGateOpenResult(String gateType, boolean success);
/**
* UDP通信错误
* @param error 错误信息
*/
void onUDPError(String error);
}
/**
* UDP设备监听接口
*/
public interface UDPDeviceListener {
/**
* 设备信息更新
* @param deviceInfo 设备信息
*/
void onDeviceInfoUpdate(String deviceInfo);
/**
* 设备连接状态变化
* @param connected 是否连接
*/
void onDeviceConnectionChange(boolean connected);
}
private OxUDP() {
executorService = Executors.newCachedThreadPool();
scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
mainHandler = new Handler(Looper.getMainLooper());
}
/**
* 获取单例实例
*/
public static synchronized OxUDP getInstance() {
if (instance == null) {
instance = new OxUDP();
}
return instance;
}
/**
* 初始化UDP连接
* @param context 应用上下文
*/
public void initUDP(Context context) {
this.context = context.getApplicationContext();
Log.i(TAG, "开始初始化UDP连接...");
executorService.execute(() -> {
try {
// 更新设备信息
updateDeviceUDP();
isInitialized = true;
Log.i(TAG, "UDP初始化成功");
notifyDeviceConnectionChange(true);
} catch (Exception e) {
Log.e(TAG, "UDP初始化失败", e);
notifyUDPError("UDP初始化失败: " + e.getMessage());
isInitialized = false;
notifyDeviceConnectionChange(false);
}
});
}
/**
* 更新当前连接UDP的设备信息到命令中
*/
private void updateDeviceUDP() {
Log.d(TAG, "开始更新设备UDP信息...");
try {
// 发送设备查询命令
String response = sendUDPCommand(udp_device_cmd);
if (response != null && !response.isEmpty()) {
Log.d(TAG, "updateDeviceUDP 响应: " + response);
// 更新设备返回的数据
udp_device_res = response;
// 更新各种命令的设备信息
udp_state_cmd = updateCmdDeviceInfo(response, udp_state_cmd);
udp_open_a_cmd = updateCmdDeviceInfo(response, udp_open_a_cmd);
udp_open_b_cmd = updateCmdDeviceInfo(response, udp_open_b_cmd);
udp_gate_a_close_time_cmd = updateCmdDeviceInfo(response, udp_gate_a_close_time_cmd);
Log.i(TAG, "设备信息更新成功");
notifyDeviceInfoUpdate(response);
} else {
Log.w(TAG, "设备返回数据为空");
notifyUDPError("设备返回数据为空");
}
} catch (Exception e) {
Log.e(TAG, "更新设备UDP信息失败", e);
notifyUDPError("更新设备信息失败: " + e.getMessage());
}
}
/**
* 更新命令中的设备信息
* @param deviceRes 设备返回的数据
* @param cmd 要更新的命令
* @return 更新后的命令
*/
private String updateCmdDeviceInfo(String deviceRes, String cmd) {
try {
String[] resDeviceArr = getCmdArr(deviceRes);
String[] cmdArr = getCmdArr(cmd);
// 替换cmd中的4-7位索引3-6
for (int i = 4; i <= 7; i++) {
if (i < resDeviceArr.length && i < cmdArr.length) {
cmdArr[i] = resDeviceArr[i];
}
}
// 重新组合命令
StringBuilder result = new StringBuilder();
for (int i = 0; i < cmdArr.length; i++) {
if (i > 0) result.append(" ");
result.append(cmdArr[i]);
}
String updatedCmd = result.toString();
Log.d(TAG, "updateCmdDeviceInfo: " + updatedCmd);
return updatedCmd;
} catch (Exception e) {
Log.e(TAG, "更新命令设备信息失败", e);
return cmd; // 返回原命令
}
}
/**
* 将命令字符串转换为数组
* @param cmd 命令字符串 "17 94 00 00 ..."
* @return 命令数组
*/
private String[] getCmdArr(String cmd) {
return cmd.trim().split("\\s+");
}
/**
* 将命令字符串转换为字节数组
* @param cmd 命令字符串 "17 94 00 00 ..."
* @return 字节数组
*/
private byte[] getCmdBytes(String cmd) {
String[] hexStrings = getCmdArr(cmd);
byte[] bytes = new byte[hexStrings.length];
for (int i = 0; i < hexStrings.length; i++) {
try {
bytes[i] = (byte) Integer.parseInt(hexStrings[i], 16);
} catch (NumberFormatException e) {
Log.e(TAG, "解析十六进制字符串失败: " + hexStrings[i], e);
bytes[i] = 0;
}
}
return bytes;
}
/**
* 将字节数组转换为十六进制字符串
* @param bytes 字节数组
* @return 十六进制字符串 "17 94 00 00 ..."
*/
private String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
if (i > 0) sb.append(" ");
sb.append(String.format("%02X", bytes[i] & 0xFF));
}
return sb.toString();
}
/**
* 发送UDP命令并获取响应
* @param command 要发送的命令
* @return 响应数据
*/
private String sendUDPCommand(String command) {
DatagramSocket socket = null;
try {
// 创建UDP套接字
socket = new DatagramSocket();
socket.setSoTimeout(UDP_TIMEOUT);
// 准备发送数据
byte[] sendData = getCmdBytes(command);
InetAddress serverAddress = InetAddress.getByName(UDP_IP);
DatagramPacket sendPacket = new DatagramPacket(
sendData, sendData.length, serverAddress, UDP_SEND_PORT);
Log.d(TAG, "发送UDP命令到 " + UDP_IP + ":" + UDP_SEND_PORT + " - " + command);
// 发送数据
socket.send(sendPacket);
// 接收响应
byte[] receiveData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(receivePacket);
// 解析响应
byte[] responseBytes = new byte[receivePacket.getLength()];
System.arraycopy(receiveData, 0, responseBytes, 0, receivePacket.getLength());
String response = bytesToHexString(responseBytes);
Log.d(TAG, "收到UDP响应: " + response);
return response;
} catch (Exception e) {
Log.e(TAG, "发送UDP命令失败: " + command, e);
return null;
} finally {
if (socket != null && !socket.isClosed()) {
socket.close();
}
}
}
/**
* 开始门禁状态轮询
*/
public void startPolling() {
if (!isInitialized) {
Log.w(TAG, "UDP未初始化,无法开始轮询");
return;
}
if (isPolling) {
Log.w(TAG, "轮询已在进行中");
return;
}
Log.i(TAG, "开始门禁状态轮询,间隔: " + POLLING_INTERVAL + "ms");
isPolling = true;
pollingTask = scheduledExecutor.scheduleWithFixedDelay(() -> {
try {
queryGateState();
} catch (Exception e) {
Log.e(TAG, "轮询过程中发生错误", e);
}
}, 0, POLLING_INTERVAL, TimeUnit.MILLISECONDS);
}
/**
* 停止门禁状态轮询
*/
public void stopPolling() {
if (!isPolling) {
return;
}
Log.i(TAG, "停止门禁状态轮询");
isPolling = false;
if (pollingTask != null && !pollingTask.isCancelled()) {
pollingTask.cancel(true);
pollingTask = null;
}
}
/**
* 查询门禁状态
*/
private void queryGateState() {
try {
String response = sendUDPCommand(udp_state_cmd);
if (response != null && !response.isEmpty()) {
// 解析门禁状态
parseGateState(response);
} else {
Log.w(TAG, "查询门禁状态失败,响应为空");
}
} catch (Exception e) {
Log.e(TAG, "查询门禁状态失败", e);
notifyUDPError("查询门禁状态失败: " + e.getMessage());
}
}
/**
* 解析门禁状态
* @param response 响应数据
*/
private void parseGateState(String response) {
try {
String[] responseArr = getCmdArr(response);
// 根据协议解析门禁状态这里需要根据实际协议调整
// 假设第8位表示A门状态第9位表示B门状态
boolean gateAState = false;
boolean gateBState = false;
if (responseArr.length > 8) {
// 解析A门状态根据实际协议调整
int aStateValue = Integer.parseInt(responseArr[8], 16);
gateAState = (aStateValue & 0x01) != 0;
}
if (responseArr.length > 9) {
// 解析B门状态根据实际协议调整
int bStateValue = Integer.parseInt(responseArr[9], 16);
gateBState = (bStateValue & 0x01) != 0;
}
Log.d(TAG, "门禁状态 - A门: " + (gateAState ? "开启" : "关闭") +
", B门: " + (gateBState ? "开启" : "关闭"));
notifyGateStateUpdate(gateAState, gateBState, response);
} catch (Exception e) {
Log.e(TAG, "解析门禁状态失败", e);
notifyUDPError("解析门禁状态失败: " + e.getMessage());
}
}
/**
* 打开A门进门
*/
public void openGateA() {
Log.i(TAG, "执行开启A门命令");
executorService.execute(() -> {
try {
String response = sendUDPCommand(udp_open_a_cmd);
boolean success = response != null && !response.isEmpty();
Log.i(TAG, "开启A门结果: " + (success ? "成功" : "失败"));
notifyGateOpenResult("A", success);
} catch (Exception e) {
Log.e(TAG, "开启A门失败", e);
notifyGateOpenResult("A", false);
notifyUDPError("开启A门失败: " + e.getMessage());
}
});
}
/**
* 打开B门出门
*/
public void openGateB() {
Log.i(TAG, "执行开启B门命令");
executorService.execute(() -> {
try {
String response = sendUDPCommand(udp_open_b_cmd);
boolean success = response != null && !response.isEmpty();
Log.i(TAG, "开启B门结果: " + (success ? "成功" : "失败"));
notifyGateOpenResult("B", success);
} catch (Exception e) {
Log.e(TAG, "开启B门失败", e);
notifyGateOpenResult("B", false);
notifyUDPError("开启B门失败: " + e.getMessage());
}
});
}
/**
* 设置A门关闭时间
* @param seconds 关闭时间
*/
public void setGateACloseTime(int seconds) {
this.udp_gate_a_close_time = seconds;
Log.i(TAG, "设置A门关闭时间: " + seconds + "秒");
executorService.execute(() -> {
try {
// 更新命令中的时间参数需要根据实际协议调整
// 这里假设第10位是时间参数
String[] cmdArr = getCmdArr(udp_gate_a_close_time_cmd);
if (cmdArr.length > 10) {
cmdArr[10] = String.format("%02X", seconds);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < cmdArr.length; i++) {
if (i > 0) sb.append(" ");
sb.append(cmdArr[i]);
}
udp_gate_a_close_time_cmd = sb.toString();
}
String response = sendUDPCommand(udp_gate_a_close_time_cmd);
boolean success = response != null && !response.isEmpty();
Log.i(TAG, "设置A门关闭时间结果: " + (success ? "成功" : "失败"));
} catch (Exception e) {
Log.e(TAG, "设置A门关闭时间失败", e);
notifyUDPError("设置A门关闭时间失败: " + e.getMessage());
}
});
}
/**
* 设置状态监听器
*/
public void setStateListener(UDPStateListener listener) {
this.stateListener = listener;
}
/**
* 设置设备监听器
*/
public void setDeviceListener(UDPDeviceListener listener) {
this.deviceListener = listener;
}
/**
* 获取初始化状态
*/
public boolean isInitialized() {
return isInitialized;
}
/**
* 获取轮询状态
*/
public boolean isPolling() {
return isPolling;
}
/**
* 获取设备返回数据
*/
public String getDeviceResponse() {
return udp_device_res;
}
/**
* 获取A门关闭时间
*/
public int getGateACloseTime() {
return udp_gate_a_close_time;
}
/**
* 停止UDP服务
*/
public void stop() {
Log.i(TAG, "停止UDP服务");
stopPolling();
isInitialized = false;
notifyDeviceConnectionChange(false);
}
/**
* 释放资源
*/
public void release() {
Log.i(TAG, "释放UDP资源");
stop();
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown();
}
if (scheduledExecutor != null && !scheduledExecutor.isShutdown()) {
scheduledExecutor.shutdown();
}
stateListener = null;
deviceListener = null;
}
// 通知方法
private void notifyGateStateUpdate(boolean gateAState, boolean gateBState, String rawData) {
if (stateListener != null) {
mainHandler.post(() -> stateListener.onGateStateUpdate(gateAState, gateBState, rawData));
}
}
private void notifyGateOpenResult(String gateType, boolean success) {
if (stateListener != null) {
mainHandler.post(() -> stateListener.onGateOpenResult(gateType, success));
}
}
private void notifyUDPError(String error) {
if (stateListener != null) {
mainHandler.post(() -> stateListener.onUDPError(error));
}
}
private void notifyDeviceInfoUpdate(String deviceInfo) {
if (deviceListener != null) {
mainHandler.post(() -> deviceListener.onDeviceInfoUpdate(deviceInfo));
}
}
private void notifyDeviceConnectionChange(boolean connected) {
if (deviceListener != null) {
mainHandler.post(() -> deviceListener.onDeviceConnectionChange(connected));
}
}
}

296
app/src/main/java/com/ouxuan/oxface/device/OxUDPUsageExample.java

@ -0,0 +1,296 @@
package com.ouxuan.oxface.device;
import android.content.Context;
import android.util.Log;
/**
* OxUDP门禁控制使用示例
* 展示如何在人脸识别界面中集成门禁UDP控制功能
*
* @author AI Assistant
* @version 1.0
*/
public class OxUDPUsageExample {
private static final String TAG = "OxUDPUsageExample";
private OxUDP oxUDP;
private Context context;
public OxUDPUsageExample(Context context) {
this.context = context;
this.oxUDP = OxUDP.getInstance();
}
/**
* 在人脸识别界面初始化UDP门禁控制
*/
public void initializeInFaceActivity() {
// 设置状态监听器
oxUDP.setStateListener(new OxUDP.UDPStateListener() {
@Override
public void onGateStateUpdate(boolean gateAState, boolean gateBState, String rawData) {
Log.i(TAG, "门禁状态更新 - A门: " + (gateAState ? "开启" : "关闭") +
", B门: " + (gateBState ? "开启" : "关闭"));
// 在人脸识别界面更新门禁状态显示
updateGateStatusUI(gateAState, gateBState);
// 根据门禁状态执行相应逻辑
handleGateStateChange(gateAState, gateBState);
}
@Override
public void onGateOpenResult(String gateType, boolean success) {
Log.i(TAG, gateType + "门开启结果: " + (success ? "成功" : "失败"));
if (success) {
// 门开启成功显示通过提示
showGateOpenSuccessMessage(gateType);
} else {
// 门开启失败显示错误信息
showGateOpenFailedMessage(gateType);
}
}
@Override
public void onUDPError(String error) {
Log.e(TAG, "UDP通信错误: " + error);
// 显示错误信息给用户
showErrorMessage("门禁通信异常: " + error);
}
});
// 设置设备监听器
oxUDP.setDeviceListener(new OxUDP.UDPDeviceListener() {
@Override
public void onDeviceInfoUpdate(String deviceInfo) {
Log.i(TAG, "设备信息更新: " + deviceInfo);
// 可以保存设备信息用于后续使用
}
@Override
public void onDeviceConnectionChange(boolean connected) {
Log.i(TAG, "设备连接状态: " + (connected ? "已连接" : "已断开"));
if (connected) {
// 设备连接成功开始轮询
startGatePolling();
} else {
// 设备连接失败显示错误信息
showErrorMessage("门禁设备连接失败");
}
}
});
// 初始化UDP连接
oxUDP.initUDP(context);
}
/**
* 开始门禁状态轮询
*/
public void startGatePolling() {
Log.i(TAG, "开始门禁状态轮询");
oxUDP.startPolling();
}
/**
* 停止门禁状态轮询
*/
public void stopGatePolling() {
Log.i(TAG, "停止门禁状态轮询");
oxUDP.stopPolling();
}
/**
* 人脸识别成功后开门处理
* @param isEntry true: 进门(开A门), false: 出门(开B门)
*/
public void handleFaceRecognitionSuccess(boolean isEntry) {
Log.i(TAG, "人脸识别成功,准备开门: " + (isEntry ? "进门(A门)" : "出门(B门)"));
if (isEntry) {
// 进门 - 开启A门
oxUDP.openGateA();
} else {
// 出门 - 开启B门
oxUDP.openGateB();
}
}
/**
* 更新界面上的门禁状态显示
* @param gateAState A门状态
* @param gateBState B门状态
*/
private void updateGateStatusUI(boolean gateAState, boolean gateBState) {
// 在人脸识别界面更新门禁状态显示
// 这里可以更新状态指示灯文字显示等
Log.d(TAG, "更新UI - A门状态: " + (gateAState ? "开启" : "关闭") +
", B门状态: " + (gateBState ? "开启" : "关闭"));
// 示例更新状态文本
// tvGateAStatus.setText("A门: " + (gateAState ? "开启" : "关闭"));
// tvGateBStatus.setText("B门: " + (gateBState ? "开启" : "关闭"));
// 示例更新状态指示器颜色
// ivGateAIndicator.setImageResource(gateAState ? R.drawable.gate_open : R.drawable.gate_close);
// ivGateBIndicator.setImageResource(gateBState ? R.drawable.gate_open : R.drawable.gate_close);
}
/**
* 处理门禁状态变化
* @param gateAState A门状态
* @param gateBState B门状态
*/
private void handleGateStateChange(boolean gateAState, boolean gateBState) {
// 根据门禁状态执行相应的业务逻辑
if (gateAState && gateBState) {
// 两个门都开启可能需要特殊处理
Log.w(TAG, "警告:A门和B门同时开启");
}
// 可以根据门的状态来调整人脸识别的流程
// 例如只有在门关闭时才允许进行人脸识别
}
/**
* 显示门开启成功消息
* @param gateType 门类型
*/
private void showGateOpenSuccessMessage(String gateType) {
String message = gateType + "门已开启,请通过";
Log.i(TAG, message);
// 在界面上显示成功信息
// Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
// 或者显示在界面的状态栏中
// tvStatusMessage.setText(message);
// tvStatusMessage.setTextColor(Color.GREEN);
}
/**
* 显示门开启失败消息
* @param gateType 门类型
*/
private void showGateOpenFailedMessage(String gateType) {
String message = gateType + "门开启失败,请重试";
Log.e(TAG, message);
// 在界面上显示失败信息
// Toast.makeText(context, message, Toast.LENGTH_LONG).show();
// tvStatusMessage.setText(message);
// tvStatusMessage.setTextColor(Color.RED);
}
/**
* 显示错误消息
* @param error 错误信息
*/
private void showErrorMessage(String error) {
Log.e(TAG, "显示错误消息: " + error);
// 在界面上显示错误信息
// Toast.makeText(context, error, Toast.LENGTH_LONG).show();
// 或者在状态栏显示
// tvStatusMessage.setText(error);
// tvStatusMessage.setTextColor(Color.RED);
}
/**
* 设置A门关闭时间
* @param seconds 关闭时间
*/
public void setGateACloseTime(int seconds) {
Log.i(TAG, "设置A门关闭时间: " + seconds + "秒");
oxUDP.setGateACloseTime(seconds);
}
/**
* 获取当前门禁状态信息
*/
public void getGateStatusInfo() {
boolean isInitialized = oxUDP.isInitialized();
boolean isPolling = oxUDP.isPolling();
String deviceResponse = oxUDP.getDeviceResponse();
int closeTime = oxUDP.getGateACloseTime();
Log.i(TAG, "门禁状态信息:");
Log.i(TAG, "- 初始化状态: " + (isInitialized ? "已初始化" : "未初始化"));
Log.i(TAG, "- 轮询状态: " + (isPolling ? "进行中" : "已停止"));
Log.i(TAG, "- 设备响应: " + deviceResponse);
Log.i(TAG, "- A门关闭时间: " + closeTime + "秒");
}
/**
* 清理资源在Activity销毁时调用
*/
public void cleanup() {
Log.i(TAG, "清理UDP门禁控制资源");
oxUDP.stop();
}
/**
* 释放所有资源在应用退出时调用
*/
public void release() {
Log.i(TAG, "释放UDP门禁控制所有资源");
oxUDP.release();
}
/**
* 在人脸识别Activity中的完整集成示例
*/
public static class FaceActivityIntegrationExample {
private OxUDPUsageExample udpExample;
/**
* 在onCreate中初始化
*/
public void onCreateInitialize(Context context) {
udpExample = new OxUDPUsageExample(context);
udpExample.initializeInFaceActivity();
// 设置A门关闭时间为3秒
udpExample.setGateACloseTime(3);
}
/**
* 在onResume中开始轮询
*/
public void onResumeStartPolling() {
if (udpExample != null) {
udpExample.startGatePolling();
}
}
/**
* 在onPause中停止轮询
*/
public void onPauseStopPolling() {
if (udpExample != null) {
udpExample.stopGatePolling();
}
}
/**
* 在onDestroy中清理资源
*/
public void onDestroyCleanup() {
if (udpExample != null) {
udpExample.cleanup();
}
}
/**
* 人脸识别成功回调处理
*/
public void onFaceRecognitionSuccess(boolean isEntryGate) {
if (udpExample != null) {
udpExample.handleFaceRecognitionSuccess(isEntryGate);
}
}
}
}
Loading…
Cancel
Save