新增机器人眼睛UI,优化逻辑代码、提高性能响应,提高代码易读性和健壮性
This commit is contained in:
parent
c8aa3c46c3
commit
c5338259ec
@ -2,6 +2,7 @@ package com.ismart.ib86.app;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
@ -10,6 +11,7 @@ import android.view.WindowInsetsController;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
@ -24,10 +26,11 @@ import com.ismart.ib86.feature.serial.SerialPort.ASR5515DeviceManager;
|
|||||||
import com.ismart.ib86.feature.serial.SerialPort.ASR5515Protocol;
|
import com.ismart.ib86.feature.serial.SerialPort.ASR5515Protocol;
|
||||||
import com.ismart.ib86.common.utils.LogManager;
|
import com.ismart.ib86.common.utils.LogManager;
|
||||||
import com.ismart.ib86.feature.gpio.GpioTest;
|
import com.ismart.ib86.feature.gpio.GpioTest;
|
||||||
|
import com.ismart.ib86.view.RobotEyesView;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
private static final String TAG = "MainActivity";
|
private static final String TAG = "MainActivity";
|
||||||
private static final String DEVICE_PATH = "/dev/ttyS2";
|
private static final String DEVICE_PATH = "/dev/ttyS3";
|
||||||
private static final int BAUD_RATE = 921600;
|
private static final int BAUD_RATE = 921600;
|
||||||
|
|
||||||
// 权限请求码
|
// 权限请求码
|
||||||
@ -40,15 +43,38 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private static final int BT_POWER_EN = 75;
|
private static final int BT_POWER_EN = 75;
|
||||||
private ASR5515DeviceManager deviceManager;
|
private ASR5515DeviceManager deviceManager;
|
||||||
private Handler handler = new Handler();
|
// 使用弱引用避免内存泄漏
|
||||||
private GpioTest gpioTest;
|
private Handler handler = new Handler(new Handler.Callback() {
|
||||||
|
@Override
|
||||||
|
public boolean handleMessage(@NonNull android.os.Message msg) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
private Runnable wearDetectionRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// 发送佩戴检测请求
|
||||||
|
deviceManager.sendWearDetectionRequest();
|
||||||
|
|
||||||
|
// 1秒后再次执行
|
||||||
|
handler.postDelayed(this, 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
private GpioManager gpioManager;
|
private GpioManager gpioManager;
|
||||||
|
|
||||||
|
private RelativeLayout mainLayout;
|
||||||
|
private RobotEyesView robotEyesView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
mainLayout = findViewById(R.id.main_layout);
|
||||||
|
mainLayout.setBackgroundColor(Color.BLACK);
|
||||||
|
robotEyesView = new RobotEyesView(this);
|
||||||
|
mainLayout.addView(robotEyesView);
|
||||||
|
|
||||||
// 检查并请求必要的权限
|
// 检查并请求必要的权限
|
||||||
checkAndRequestPermissions();
|
checkAndRequestPermissions();
|
||||||
|
|
||||||
@ -210,39 +236,50 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
// deviceManager.queryBtVersion();
|
// deviceManager.queryBtVersion();
|
||||||
// }
|
// }
|
||||||
// }, 2000);
|
// }, 2000);
|
||||||
deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.HR);
|
// deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.HR);
|
||||||
deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.SPO2);
|
// deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.SPO2);
|
||||||
handler.postDelayed(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
deviceManager.startGH3220Measure(ASR5515Protocol.GH3220MeasureType.SPO2);
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
// handler.postDelayed(new Runnable() {
|
// handler.postDelayed(new Runnable() {
|
||||||
// @Override
|
// @Override
|
||||||
// public void run() {
|
// public void run() {
|
||||||
// deviceManager.sendWearDetectionRequest();
|
// deviceManager.startGH3220Measure(ASR5515Protocol.GH3220MeasureType.SPO2);
|
||||||
// }
|
// }
|
||||||
// }, 4000);
|
// }, 1000);
|
||||||
|
|
||||||
|
handler.postDelayed(wearDetectionRunnable, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
// 移除所有Handler消息和回调,避免内存泄漏
|
||||||
|
if (handler != null) {
|
||||||
handler.removeCallbacksAndMessages(null);
|
handler.removeCallbacksAndMessages(null);
|
||||||
|
handler = null;
|
||||||
|
}
|
||||||
|
|
||||||
// 移至后台线程执行耗时操作,避免ANR
|
// 移至后台线程执行耗时操作,避免ANR
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
// if (deviceManager != null) {
|
try {
|
||||||
// deviceManager.syncHostStatus(false);
|
// 停止所有测量
|
||||||
// deviceManager.close();
|
if (deviceManager != null) {
|
||||||
// }
|
deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.HR);
|
||||||
|
deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.SPO2);
|
||||||
|
deviceManager.syncHostStatus(false);
|
||||||
|
deviceManager.close();
|
||||||
|
deviceManager = null;
|
||||||
|
}
|
||||||
|
|
||||||
// 释放GPIO测试资源
|
// 关闭GPIO电源
|
||||||
if (gpioTest != null) {
|
if (gpioManager != null) {
|
||||||
gpioTest.release();
|
try {
|
||||||
gpioTest = null;
|
gpioManager.setValue(BT_POWER_EN, GpioManager.VALUE_LOW);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "关闭GPIO电源失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
gpioManager = null;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "资源释放过程中发生错误: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,47 @@ import com.ismart.ib86.feature.gpio.GpioManager;
|
|||||||
*/
|
*/
|
||||||
public class ASR5515DeviceManager {
|
public class ASR5515DeviceManager {
|
||||||
private static final String TAG = "ASR5515DeviceManager";
|
private static final String TAG = "ASR5515DeviceManager";
|
||||||
|
|
||||||
|
// 设备状态标志
|
||||||
|
private volatile boolean isDeviceOpen = false;
|
||||||
|
private final Object sendLock = new Object(); // 发送数据的同步锁
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查设备是否就绪
|
||||||
|
* @return true 如果设备已打开且就绪
|
||||||
|
*/
|
||||||
|
private boolean isDeviceReady() {
|
||||||
|
return isDeviceOpen && serialPortHelper != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全发送数据的方法
|
||||||
|
* @param data 要发送的数据
|
||||||
|
* @return true 如果发送成功
|
||||||
|
*/
|
||||||
|
protected boolean safeSendData(byte[] data) {
|
||||||
|
if (!isDeviceReady()) {
|
||||||
|
LogManager.e(TAG, "设备未就绪,无法发送数据");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (sendLock) {
|
||||||
|
try {
|
||||||
|
serialPortHelper.sendAsync(data);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "发送数据失败: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
private static final int GPIO_BT_WAKE = 33; // 蓝牙唤醒GPIO
|
private static final int GPIO_BT_WAKE = 33; // 蓝牙唤醒GPIO
|
||||||
|
|
||||||
private final SerialPortHelper serialPortHelper;
|
private final SerialPortHelper serialPortHelper;
|
||||||
private final Handler mainHandler;
|
private final Handler mainHandler;
|
||||||
private final GpioManager gpioManager;
|
private final GpioManager gpioManager;
|
||||||
|
private final Object gpioLock = new Object(); // GPIO操作的同步锁
|
||||||
|
private volatile boolean isInitialized = false; // 初始化状态标志
|
||||||
// 细分回调实例
|
// 细分回调实例
|
||||||
private DeviceCheckListener deviceCheckListener;
|
private DeviceCheckListener deviceCheckListener;
|
||||||
private DeviceControlListener deviceControlListener;
|
private DeviceControlListener deviceControlListener;
|
||||||
@ -106,16 +142,36 @@ public class ASR5515DeviceManager {
|
|||||||
* @param context 上下文
|
* @param context 上下文
|
||||||
* @param devicePath 设备路径
|
* @param devicePath 设备路径
|
||||||
* @param baudRate 波特率
|
* @param baudRate 波特率
|
||||||
|
* @throws IllegalStateException 如果串口打开失败
|
||||||
*/
|
*/
|
||||||
public ASR5515DeviceManager(Context context, String devicePath, int baudRate) {
|
public ASR5515DeviceManager(Context context, String devicePath, int baudRate) {
|
||||||
|
synchronized (sendLock) {
|
||||||
|
try {
|
||||||
serialPortHelper = new SerialPortHelper(devicePath, baudRate);
|
serialPortHelper = new SerialPortHelper(devicePath, baudRate);
|
||||||
mainHandler = new Handler(Looper.getMainLooper());
|
mainHandler = new Handler(Looper.getMainLooper());
|
||||||
gpioManager = GpioManager.getInstance();
|
gpioManager = GpioManager.getInstance();
|
||||||
serialPortHelper.setSimulationMode(false);
|
serialPortHelper.setSimulationMode(false);
|
||||||
|
|
||||||
// 初始化串口
|
// 初始化串口
|
||||||
boolean result = serialPortHelper.open();
|
boolean result = serialPortHelper.open();
|
||||||
if (!result) {
|
if (!result) {
|
||||||
LogManager.e(TAG, "Failed to open serial port: " + devicePath);
|
String errorMsg = "Failed to open serial port: " + devicePath;
|
||||||
|
LogManager.e(TAG, errorMsg);
|
||||||
|
updateDeviceState(false);
|
||||||
|
isInitialized = false;
|
||||||
|
// 记录错误但不抛出异常,允许应用继续运行
|
||||||
|
// 在实际使用时会检查isDeviceOpen状态
|
||||||
|
} else {
|
||||||
|
updateDeviceState(true);
|
||||||
|
isInitialized = true;
|
||||||
|
LogManager.i(TAG, "Serial port opened successfully: " + devicePath);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "Device initialization failed: " + e.getMessage());
|
||||||
|
updateDeviceState(false);
|
||||||
|
isInitialized = false;
|
||||||
|
throw new IllegalStateException("Failed to initialize device manager", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置设备状态回调
|
// 设置设备状态回调
|
||||||
@ -346,28 +402,72 @@ public class ASR5515DeviceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查设备状态
|
* 检查设备是否已打开且可用
|
||||||
|
* @return true 如果设备已打开且可用
|
||||||
*/
|
*/
|
||||||
public void checkDevice() {
|
public boolean isDeviceAvailable() {
|
||||||
|
return isDeviceReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查设备状态
|
||||||
|
* @return true 如果命令发送成功
|
||||||
|
*/
|
||||||
|
public boolean checkDevice() {
|
||||||
|
if (!isDeviceReady()) {
|
||||||
|
LogManager.e(TAG, "设备未就绪,无法检查设备状态");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
wakeupDevice();
|
wakeupDevice();
|
||||||
serialPortHelper.checkDevice();
|
serialPortHelper.checkDevice();
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "检查设备状态失败: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重启设备
|
* 重启设备
|
||||||
|
* @return true 如果命令发送成功
|
||||||
*/
|
*/
|
||||||
public void restartDevice() {
|
public boolean restartDevice() {
|
||||||
|
if (!isDeviceReady()) {
|
||||||
|
LogManager.e(TAG, "设备未就绪,无法重启设备");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
wakeupDevice();
|
wakeupDevice();
|
||||||
serialPortHelper.restartDevice();
|
serialPortHelper.restartDevice();
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "重启设备失败: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制日志输出
|
* 控制日志输出
|
||||||
* @param enable 是否启用
|
* @param enable 是否启用
|
||||||
|
* @return true 如果命令发送成功
|
||||||
*/
|
*/
|
||||||
public void setLogControl(boolean enable) {
|
public boolean setLogControl(boolean enable) {
|
||||||
|
if (!isDeviceReady()) {
|
||||||
|
LogManager.e(TAG, "设备未就绪,无法控制日志输出");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
wakeupDevice();
|
wakeupDevice();
|
||||||
serialPortHelper.setLogControl(enable);
|
serialPortHelper.setLogControl(enable);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "控制日志输出失败: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -396,10 +496,31 @@ public class ASR5515DeviceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭设备
|
* 设备状态变化的回调接口
|
||||||
*/
|
*/
|
||||||
public void close() {
|
public interface DeviceStateCallback {
|
||||||
serialPortHelper.close();
|
void onDeviceStateChanged(boolean isOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeviceStateCallback deviceStateCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置设备状态变化回调
|
||||||
|
* @param callback 回调接口
|
||||||
|
*/
|
||||||
|
public void setDeviceStateCallback(DeviceStateCallback callback) {
|
||||||
|
this.deviceStateCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新设备状态并通知回调
|
||||||
|
* @param newState 新的设备状态
|
||||||
|
*/
|
||||||
|
private void updateDeviceState(boolean newState) {
|
||||||
|
isDeviceOpen = newState;
|
||||||
|
if (deviceStateCallback != null) {
|
||||||
|
mainHandler.post(() -> deviceStateCallback.onDeviceStateChanged(newState));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -473,8 +594,10 @@ public class ASR5515DeviceManager {
|
|||||||
/**
|
/**
|
||||||
* 唤醒设备
|
* 唤醒设备
|
||||||
* 通过GPIO33唤醒蓝牙,ASR休眠时会自动发送'w'字符
|
* 通过GPIO33唤醒蓝牙,ASR休眠时会自动发送'w'字符
|
||||||
|
* 使用同步锁确保GPIO操作的线程安全
|
||||||
*/
|
*/
|
||||||
public void wakeupDevice() {
|
public void wakeupDevice() {
|
||||||
|
synchronized (gpioLock) {
|
||||||
try {
|
try {
|
||||||
// 配置GPIO33为输出模式
|
// 配置GPIO33为输出模式
|
||||||
gpioManager.exportGpio(GPIO_BT_WAKE);
|
gpioManager.exportGpio(GPIO_BT_WAKE);
|
||||||
@ -489,8 +612,67 @@ public class ASR5515DeviceManager {
|
|||||||
// 拉高GPIO33
|
// 拉高GPIO33
|
||||||
gpioManager.setValue(GPIO_BT_WAKE, 1);
|
gpioManager.setValue(GPIO_BT_WAKE, 1);
|
||||||
|
|
||||||
|
//LogManager.d(TAG, "设备唤醒成功");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
//LogManager.e(TAG, "设备唤醒被中断: " + e.getMessage());
|
||||||
|
Thread.currentThread().interrupt(); // 重置中断状态
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogManager.e(TAG, "Failed to wakeup bluetooth: " + e.getMessage());
|
//LogManager.e(TAG, "设备唤醒失败: " + e.getMessage());
|
||||||
|
// 尝试恢复GPIO状态
|
||||||
|
try {
|
||||||
|
gpioManager.setValue(GPIO_BT_WAKE, 1); // 确保GPIO处于高电平
|
||||||
|
} catch (Exception ex) {
|
||||||
|
//LogManager.e(TAG, "恢复GPIO状态失败: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 关闭设备,释放所有资源
|
||||||
|
*/
|
||||||
|
public void close() {
|
||||||
|
synchronized (sendLock) {
|
||||||
|
try {
|
||||||
|
// 清除所有回调,避免内存泄漏
|
||||||
|
clearAllListeners();
|
||||||
|
|
||||||
|
// 关闭串口
|
||||||
|
if (serialPortHelper != null) {
|
||||||
|
serialPortHelper.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除所有Handler消息和回调
|
||||||
|
if (mainHandler != null) {
|
||||||
|
mainHandler.removeCallbacksAndMessages(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新设备状态
|
||||||
|
updateDeviceState(false);
|
||||||
|
isInitialized = false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "Error closing device manager: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除所有监听器,避免内存泄漏
|
||||||
|
*/
|
||||||
|
private void clearAllListeners() {
|
||||||
|
deviceCheckListener = null;
|
||||||
|
deviceControlListener = null;
|
||||||
|
logControlListener = null;
|
||||||
|
btVersionListener = null;
|
||||||
|
btUpgradeListener = null;
|
||||||
|
hostStatusListener = null;
|
||||||
|
bootBinCheckListener = null;
|
||||||
|
collectFreqSetListener = null;
|
||||||
|
hrBpBoAutoMeasureListener = null;
|
||||||
|
hrBpBoManualMeasureListener = null;
|
||||||
|
dynamicMeasureListener = null;
|
||||||
|
wearDetectionListener = null;
|
||||||
|
gh3220MeasureListener = null;
|
||||||
|
algoResultListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -200,15 +200,6 @@ public class SerialPortHelper {
|
|||||||
this.algoResultCallback = callback;
|
this.algoResultCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送佩戴检测查询请求
|
|
||||||
*/
|
|
||||||
public void sendWearDetectionRequest() {
|
|
||||||
byte[] data = ASR5515Protocol.createWearDetectionRequest();
|
|
||||||
sendData(data, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ASR-5515协议命令发送方法
|
|
||||||
public void checkDevice() {
|
public void checkDevice() {
|
||||||
byte[] data = ASR5515Protocol.createDeviceCheckRequest();
|
byte[] data = ASR5515Protocol.createDeviceCheckRequest();
|
||||||
sendData(data, null);
|
sendData(data, null);
|
||||||
@ -306,6 +297,14 @@ public class SerialPortHelper {
|
|||||||
sendData(data, null);
|
sendData(data, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送佩戴检测查询请求
|
||||||
|
*/
|
||||||
|
public void sendWearDetectionRequest() {
|
||||||
|
byte[] data = ASR5515Protocol.createWearDetectionRequest();
|
||||||
|
sendData(data, null);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean open() {
|
public boolean open() {
|
||||||
try {
|
try {
|
||||||
LogManager.d(TAG, "Opening serial port: " + mPortName + " with baud rate: " + mBaudRate);
|
LogManager.d(TAG, "Opening serial port: " + mPortName + " with baud rate: " + mBaudRate);
|
||||||
|
78
app/src/main/java/com/ismart/ib86/view/RobotEyesView.java
Normal file
78
app/src/main/java/com/ismart/ib86/view/RobotEyesView.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package com.ismart.ib86.view;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.Transformation;
|
||||||
|
|
||||||
|
public class RobotEyesView extends View {
|
||||||
|
|
||||||
|
private Paint paint;
|
||||||
|
private float eyeWidth = 100f; // Increased size for eyes
|
||||||
|
private float eyeHeight = 100f; // Increased size for eyes
|
||||||
|
private float borderRadius = 25f; // Adjusted border radius for larger eyes
|
||||||
|
private float blinkDuration = 3000f; // 3 seconds in milliseconds
|
||||||
|
|
||||||
|
public RobotEyesView(Context context) {
|
||||||
|
super(context);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RobotEyesView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RobotEyesView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
paint = new Paint();
|
||||||
|
paint.setColor(Color.rgb(26, 249, 248));
|
||||||
|
paint.setStyle(Paint.Style.FILL);
|
||||||
|
|
||||||
|
startBlinkAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
float centerXLeft = getWidth() / 4f;
|
||||||
|
float centerXRight = getWidth() * 3 / 4f;
|
||||||
|
float centerY = getHeight() / 3f; // Set eyes to one-third of screen height
|
||||||
|
|
||||||
|
drawEye(canvas, centerXLeft, centerY);
|
||||||
|
drawEye(canvas, centerXRight, centerY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawEye(Canvas canvas, float centerX, float centerY) {
|
||||||
|
canvas.drawRoundRect(centerX - eyeWidth / 2, centerY - eyeHeight / 2,
|
||||||
|
centerX + eyeWidth / 2, centerY + eyeHeight / 2,
|
||||||
|
borderRadius, borderRadius, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startBlinkAnimation() {
|
||||||
|
final Animation animation = new Animation() {
|
||||||
|
@Override
|
||||||
|
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||||
|
if (interpolatedTime >= 0.2 && interpolatedTime < 0.25) {
|
||||||
|
eyeHeight = 20f; // Adjusted size for blinking effect
|
||||||
|
} else if (interpolatedTime >= 0.25 && interpolatedTime < 0.3) {
|
||||||
|
eyeHeight = 100f; // Reset to original size
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
animation.setDuration((long) blinkDuration);
|
||||||
|
animation.setRepeatCount(Animation.INFINITE);
|
||||||
|
startAnimation(animation);
|
||||||
|
}
|
||||||
|
}
|
@ -1,82 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="设备信息"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:layout_marginBottom="8dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_device_info"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="#F5F5F5"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:minHeight="100dp"
|
|
||||||
android:layout_marginBottom="16dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_bt_version"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="#F5F5F5"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:layout_marginBottom="16dp"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_marginBottom="8dp">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btn_check_device"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="检查设备"
|
|
||||||
android:layout_marginEnd="8dp"/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btn_restart_device"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="重启设备"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_marginBottom="8dp">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btn_query_bt_version"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="查询蓝牙版本"
|
|
||||||
android:layout_marginEnd="8dp"/>
|
|
||||||
|
|
||||||
<ToggleButton
|
|
||||||
android:id="@+id/toggle_log"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:textOn="关闭日志"
|
|
||||||
android:textOff="开启日志"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -1,23 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/main"
|
android:id="@+id/main_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:padding="16dp"
|
|
||||||
tools:context=".MainActivity">
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
<TextView
|
<com.ismart.ib86.view.RobotEyesView
|
||||||
android:id="@+id/titleTextView"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="match_parent"/>
|
||||||
android:layout_height="wrap_content"
|
</RelativeLayout>
|
||||||
android:text="iB86 功能演示"
|
|
||||||
android:textSize="24sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:layout_marginTop="32dp" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,66 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/titleTextView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="佩戴检测"
|
|
||||||
android:textSize="24sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:layout_marginTop="16dp" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/detectButton"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="检测佩戴状态"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/titleTextView"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:layout_marginTop="32dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/statusLabelTextView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="佩戴状态:"
|
|
||||||
android:textSize="18sp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/detectButton"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
android:layout_marginTop="32dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/statusTextView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="未检测"
|
|
||||||
android:textSize="18sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/statusLabelTextView"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/statusLabelTextView"
|
|
||||||
android:layout_marginStart="8dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/logTextView"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:background="#F5F5F5"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:scrollbars="vertical"
|
|
||||||
android:gravity="top|start"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/statusLabelTextView"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
android:layout_marginTop="32dp" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
Loading…
x
Reference in New Issue
Block a user