software copyright
This commit is contained in:
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
* 自然写互动课堂应用开发SDK软件 V1.0
|
||||
* PenManager - Android端蓝牙点阵笔连接管理器
|
||||
*
|
||||
* 功能说明:
|
||||
* 1. BLE 5.0蓝牙扫描与自动连接
|
||||
* 2. GATT服务发现与特征值订阅
|
||||
* 3. 点阵笔数据实时接收与解析
|
||||
* 4. 多笔同时连接管理(最多支持60支)
|
||||
* 5. 连接状态监控与自动重连
|
||||
* 6. 电量/固件版本/设备信息查询
|
||||
*/
|
||||
|
||||
package com.writech.sdk.android;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCallback;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattDescriptor;
|
||||
import android.bluetooth.BluetoothGattService;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.le.BluetoothLeScanner;
|
||||
import android.bluetooth.le.ScanCallback;
|
||||
import android.bluetooth.le.ScanFilter;
|
||||
import android.bluetooth.le.ScanResult;
|
||||
import android.bluetooth.le.ScanSettings;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* 点阵笔蓝牙连接管理器
|
||||
* 负责BLE扫描、连接、数据接收的全生命周期管理
|
||||
*/
|
||||
public class PenManager {
|
||||
|
||||
private static final String TAG = "WritechPenManager";
|
||||
|
||||
/* 自然写点阵笔GATT服务UUID(自定义) */
|
||||
private static final UUID PEN_SERVICE_UUID =
|
||||
UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB");
|
||||
|
||||
/* 笔迹数据通知特征值UUID */
|
||||
private static final UUID STROKE_DATA_CHAR_UUID =
|
||||
UUID.fromString("0000FFE1-0000-1000-8000-00805F9B34FB");
|
||||
|
||||
/* 笔控制指令写入特征值UUID */
|
||||
private static final UUID PEN_CONTROL_CHAR_UUID =
|
||||
UUID.fromString("0000FFE2-0000-1000-8000-00805F9B34FB");
|
||||
|
||||
/* 设备信息特征值UUID(电量/固件版本) */
|
||||
private static final UUID DEVICE_INFO_CHAR_UUID =
|
||||
UUID.fromString("0000FFE3-0000-1000-8000-00805F9B34FB");
|
||||
|
||||
/* CCCD描述符UUID,用于启用通知 */
|
||||
private static final UUID CCCD_UUID =
|
||||
UUID.fromString("00002902-0000-1000-8000-00805F9B34FB");
|
||||
|
||||
/* 最大同时连接数 */
|
||||
private static final int MAX_CONNECTIONS = 60;
|
||||
|
||||
/* 自动重连延迟(毫秒) */
|
||||
private static final long RECONNECT_DELAY_MS = 3000;
|
||||
|
||||
/* 扫描超时时间(毫秒) */
|
||||
private static final long SCAN_TIMEOUT_MS = 30000;
|
||||
|
||||
/* ========== 成员变量 ========== */
|
||||
|
||||
private final Context mContext;
|
||||
private final BluetoothAdapter mBluetoothAdapter;
|
||||
private BluetoothLeScanner mScanner;
|
||||
|
||||
/* 已连接的笔设备映射表(MAC地址 → GATT连接) */
|
||||
private final Map<String, BluetoothGatt> mConnectedPens = new ConcurrentHashMap<>();
|
||||
|
||||
/* 等待重连的设备列表 */
|
||||
private final Map<String, Integer> mReconnectAttempts = new ConcurrentHashMap<>();
|
||||
|
||||
/* 设备信息缓存(MAC地址 → 设备模型) */
|
||||
private final Map<String, PenDeviceInfo> mDeviceInfoCache = new ConcurrentHashMap<>();
|
||||
|
||||
/* 数据回调监听器列表 */
|
||||
private final List<PenDataListener> mDataListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
/* 连接状态监听器列表 */
|
||||
private final List<PenConnectionListener> mConnectionListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
/* BLE操作专用线程 */
|
||||
private HandlerThread mBleThread;
|
||||
private Handler mBleHandler;
|
||||
|
||||
/* 扫描状态标志 */
|
||||
private volatile boolean mIsScanning = false;
|
||||
|
||||
/* ========== 内部数据结构 ========== */
|
||||
|
||||
/** 笔设备信息缓存 */
|
||||
private static class PenDeviceInfo {
|
||||
String macAddress; /* MAC地址 */
|
||||
String penName; /* 笔名称 */
|
||||
String firmwareVersion; /* 固件版本 */
|
||||
int batteryLevel; /* 电量百分比 */
|
||||
long lastDataTimestamp; /* 最后一次收到数据的时间 */
|
||||
boolean isWriting; /* 是否正在书写 */
|
||||
}
|
||||
|
||||
/* ========== 对外回调接口 ========== */
|
||||
|
||||
/** 笔迹数据监听器 */
|
||||
public interface PenDataListener {
|
||||
/** 收到笔迹坐标数据 */
|
||||
void onStrokeData(String penMac, int x, int y, int pressure, long timestamp);
|
||||
/** 笔抬起事件(一笔结束) */
|
||||
void onPenUp(String penMac, long timestamp);
|
||||
/** 笔落下事件(一笔开始) */
|
||||
void onPenDown(String penMac, long timestamp);
|
||||
}
|
||||
|
||||
/** 连接状态监听器 */
|
||||
public interface PenConnectionListener {
|
||||
void onPenConnected(String penMac, String penName);
|
||||
void onPenDisconnected(String penMac, int reason);
|
||||
void onPenDiscovered(String penMac, String penName, int rssi);
|
||||
void onBatteryUpdate(String penMac, int batteryPercent);
|
||||
}
|
||||
|
||||
/* ========== 构造与初始化 ========== */
|
||||
|
||||
/**
|
||||
* 创建笔管理器实例
|
||||
* @param context Android上下文(需要蓝牙权限)
|
||||
*/
|
||||
public PenManager(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
BluetoothManager btManager =
|
||||
(BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
mBluetoothAdapter = btManager.getAdapter();
|
||||
|
||||
/* 创建BLE操作专用后台线程 */
|
||||
mBleThread = new HandlerThread("WritechBLE");
|
||||
mBleThread.start();
|
||||
mBleHandler = new Handler(mBleThread.getLooper());
|
||||
|
||||
Log.i(TAG, "PenManager初始化完成,蓝牙状态: "
|
||||
+ (mBluetoothAdapter.isEnabled() ? "已开启" : "未开启"));
|
||||
}
|
||||
|
||||
/** 注册笔迹数据监听器 */
|
||||
public void addDataListener(PenDataListener listener) {
|
||||
if (listener != null && !mDataListeners.contains(listener)) {
|
||||
mDataListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/** 移除笔迹数据监听器 */
|
||||
public void removeDataListener(PenDataListener listener) {
|
||||
mDataListeners.remove(listener);
|
||||
}
|
||||
|
||||
/** 注册连接状态监听器 */
|
||||
public void addConnectionListener(PenConnectionListener listener) {
|
||||
if (listener != null && !mConnectionListeners.contains(listener)) {
|
||||
mConnectionListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== BLE扫描 ========== */
|
||||
|
||||
/**
|
||||
* 开始扫描附近的自然写点阵笔
|
||||
* 使用低延迟模式扫描BLE设备,按服务UUID过滤
|
||||
*/
|
||||
public void startScan() {
|
||||
if (mIsScanning) {
|
||||
Log.w(TAG, "扫描已在进行中,忽略重复请求");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mBluetoothAdapter.isEnabled()) {
|
||||
Log.e(TAG, "蓝牙未开启,无法扫描");
|
||||
return;
|
||||
}
|
||||
|
||||
mScanner = mBluetoothAdapter.getBluetoothLeScanner();
|
||||
if (mScanner == null) {
|
||||
Log.e(TAG, "获取BLE扫描器失败");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 构建扫描过滤器:仅扫描包含自然写服务UUID的设备 */
|
||||
ScanFilter filter = new ScanFilter.Builder()
|
||||
.setServiceUuid(new ParcelUuid(PEN_SERVICE_UUID))
|
||||
.build();
|
||||
List<ScanFilter> filters = Collections.singletonList(filter);
|
||||
|
||||
/* 低延迟扫描设置(耗电较高,适合主动扫描场景) */
|
||||
ScanSettings settings = new ScanSettings.Builder()
|
||||
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
|
||||
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
|
||||
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
|
||||
.build();
|
||||
|
||||
mScanner.startScan(filters, settings, mScanCallback);
|
||||
mIsScanning = true;
|
||||
|
||||
/* 设置扫描超时,避免长时间扫描耗电 */
|
||||
mBleHandler.postDelayed(this::stopScan, SCAN_TIMEOUT_MS);
|
||||
|
||||
Log.i(TAG, "开始扫描自然写点阵笔...");
|
||||
}
|
||||
|
||||
/** 停止BLE扫描 */
|
||||
public void stopScan() {
|
||||
if (mIsScanning && mScanner != null) {
|
||||
mScanner.stopScan(mScanCallback);
|
||||
mIsScanning = false;
|
||||
Log.i(TAG, "停止扫描");
|
||||
}
|
||||
}
|
||||
|
||||
/** BLE扫描回调 */
|
||||
private final ScanCallback mScanCallback = new ScanCallback() {
|
||||
@Override
|
||||
public void onScanResult(int callbackType, ScanResult result) {
|
||||
BluetoothDevice device = result.getDevice();
|
||||
String mac = device.getAddress();
|
||||
String name = device.getName();
|
||||
int rssi = result.getRssi();
|
||||
|
||||
if (name == null || name.isEmpty()) {
|
||||
name = "WritechPen-" + mac.substring(mac.length() - 5);
|
||||
}
|
||||
|
||||
/* 通知上层发现了新的笔设备 */
|
||||
for (PenConnectionListener listener : mConnectionListeners) {
|
||||
listener.onPenDiscovered(mac, name, rssi);
|
||||
}
|
||||
|
||||
Log.d(TAG, "发现笔设备: " + name + " [" + mac + "] RSSI=" + rssi);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScanFailed(int errorCode) {
|
||||
mIsScanning = false;
|
||||
Log.e(TAG, "BLE扫描失败,错误码: " + errorCode);
|
||||
}
|
||||
};
|
||||
|
||||
/* ========== BLE连接管理 ========== */
|
||||
|
||||
/**
|
||||
* 连接指定MAC地址的点阵笔
|
||||
* @param macAddress 设备MAC地址
|
||||
*/
|
||||
public void connectPen(String macAddress) {
|
||||
if (mConnectedPens.size() >= MAX_CONNECTIONS) {
|
||||
Log.w(TAG, "已达最大连接数 " + MAX_CONNECTIONS + ",拒绝新连接");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mConnectedPens.containsKey(macAddress)) {
|
||||
Log.w(TAG, "设备已连接: " + macAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(macAddress);
|
||||
/* 使用TRANSPORT_LE确保走BLE通道,autoConnect=false立即连接 */
|
||||
device.connectGatt(mContext, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
|
||||
Log.i(TAG, "正在连接笔设备: " + macAddress);
|
||||
}
|
||||
|
||||
/** 断开指定笔的连接 */
|
||||
public void disconnectPen(String macAddress) {
|
||||
BluetoothGatt gatt = mConnectedPens.remove(macAddress);
|
||||
if (gatt != null) {
|
||||
gatt.disconnect();
|
||||
gatt.close();
|
||||
mReconnectAttempts.remove(macAddress);
|
||||
Log.i(TAG, "已断开笔设备: " + macAddress);
|
||||
}
|
||||
}
|
||||
|
||||
/** 断开所有已连接的笔 */
|
||||
public void disconnectAll() {
|
||||
for (Map.Entry<String, BluetoothGatt> entry : mConnectedPens.entrySet()) {
|
||||
entry.getValue().disconnect();
|
||||
entry.getValue().close();
|
||||
}
|
||||
mConnectedPens.clear();
|
||||
mReconnectAttempts.clear();
|
||||
Log.i(TAG, "已断开所有笔设备");
|
||||
}
|
||||
|
||||
/** 获取当前已连接的笔数量 */
|
||||
public int getConnectedCount() {
|
||||
return mConnectedPens.size();
|
||||
}
|
||||
|
||||
/** 获取所有已连接笔的MAC地址列表 */
|
||||
public List<String> getConnectedPenMacs() {
|
||||
return new ArrayList<>(mConnectedPens.keySet());
|
||||
}
|
||||
|
||||
/* ========== GATT回调处理 ========== */
|
||||
|
||||
/**
|
||||
* GATT连接/数据回调
|
||||
* 处理连接状态变化、服务发现、数据通知等所有BLE事件
|
||||
*/
|
||||
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
|
||||
|
||||
@Override
|
||||
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
|
||||
String mac = gatt.getDevice().getAddress();
|
||||
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
/* 连接成功,开始发现GATT服务 */
|
||||
mConnectedPens.put(mac, gatt);
|
||||
mReconnectAttempts.remove(mac);
|
||||
gatt.discoverServices();
|
||||
|
||||
String name = gatt.getDevice().getName();
|
||||
for (PenConnectionListener listener : mConnectionListeners) {
|
||||
listener.onPenConnected(mac, name != null ? name : "Unknown");
|
||||
}
|
||||
Log.i(TAG, "笔设备连接成功: " + mac + ",正在发现服务...");
|
||||
|
||||
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
/* 连接断开,尝试自动重连 */
|
||||
mConnectedPens.remove(mac);
|
||||
gatt.close();
|
||||
|
||||
for (PenConnectionListener listener : mConnectionListeners) {
|
||||
listener.onPenDisconnected(mac, status);
|
||||
}
|
||||
Log.w(TAG, "笔设备断开: " + mac + ",状态码: " + status);
|
||||
|
||||
/* 自动重连逻辑(最多尝试5次) */
|
||||
scheduleReconnect(mac);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
|
||||
if (status != BluetoothGatt.GATT_SUCCESS) {
|
||||
Log.e(TAG, "GATT服务发现失败: " + status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 查找自然写笔迹数据服务 */
|
||||
BluetoothGattService penService = gatt.getService(PEN_SERVICE_UUID);
|
||||
if (penService == null) {
|
||||
Log.e(TAG, "未找到自然写笔服务,设备可能不兼容");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 订阅笔迹数据通知特征值 */
|
||||
BluetoothGattCharacteristic strokeChar =
|
||||
penService.getCharacteristic(STROKE_DATA_CHAR_UUID);
|
||||
if (strokeChar != null) {
|
||||
gatt.setCharacteristicNotification(strokeChar, true);
|
||||
|
||||
/* 写入CCCD描述符启用通知 */
|
||||
BluetoothGattDescriptor cccd = strokeChar.getDescriptor(CCCD_UUID);
|
||||
if (cccd != null) {
|
||||
cccd.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
|
||||
gatt.writeDescriptor(cccd);
|
||||
}
|
||||
Log.i(TAG, "已订阅笔迹数据通知");
|
||||
}
|
||||
|
||||
/* 读取设备信息(电量、固件版本) */
|
||||
BluetoothGattCharacteristic infoChar =
|
||||
penService.getCharacteristic(DEVICE_INFO_CHAR_UUID);
|
||||
if (infoChar != null) {
|
||||
mBleHandler.postDelayed(() -> gatt.readCharacteristic(infoChar), 500);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicChanged(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic) {
|
||||
String mac = gatt.getDevice().getAddress();
|
||||
UUID charUuid = characteristic.getUuid();
|
||||
|
||||
if (STROKE_DATA_CHAR_UUID.equals(charUuid)) {
|
||||
/* 收到笔迹数据通知,解析并分发 */
|
||||
byte[] data = characteristic.getValue();
|
||||
parseAndDispatchStrokeData(mac, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicRead(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic,
|
||||
int status) {
|
||||
if (status != BluetoothGatt.GATT_SUCCESS) return;
|
||||
|
||||
String mac = gatt.getDevice().getAddress();
|
||||
UUID charUuid = characteristic.getUuid();
|
||||
|
||||
if (DEVICE_INFO_CHAR_UUID.equals(charUuid)) {
|
||||
/* 解析设备信息数据 */
|
||||
byte[] data = characteristic.getValue();
|
||||
parseDeviceInfo(mac, data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* ========== 数据解析与分发 ========== */
|
||||
|
||||
/**
|
||||
* 解析BLE收到的笔迹数据帧并分发给监听器
|
||||
* 数据格式(7字节紧凑编码):
|
||||
* [0-1] X坐标高16位 [2-3] Y坐标高16位
|
||||
* [4] X低4位|Y低4位 [5] 压力高8位 [6] 压力低4位|标志
|
||||
*/
|
||||
private void parseAndDispatchStrokeData(String penMac, byte[] data) {
|
||||
if (data == null || data.length < 7) {
|
||||
return;
|
||||
}
|
||||
|
||||
long timestamp = System.currentTimeMillis();
|
||||
|
||||
/* 检查帧类型标志(最低2位) */
|
||||
int flags = data[6] & 0x03;
|
||||
|
||||
if (flags == 0x01) {
|
||||
/* 笔落下事件 */
|
||||
for (PenDataListener listener : mDataListeners) {
|
||||
listener.onPenDown(penMac, timestamp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags == 0x02) {
|
||||
/* 笔抬起事件 */
|
||||
for (PenDataListener listener : mDataListeners) {
|
||||
listener.onPenUp(penMac, timestamp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 坐标数据帧(flags == 0x00) */
|
||||
int xHigh = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
|
||||
int xLow = (data[4] >> 4) & 0x0F;
|
||||
int x = (xHigh << 4) | xLow;
|
||||
|
||||
int yHigh = ((data[2] & 0xFF) << 8) | (data[3] & 0xFF);
|
||||
int yLow = data[4] & 0x0F;
|
||||
int y = (yHigh << 4) | yLow;
|
||||
|
||||
int pHigh = data[5] & 0xFF;
|
||||
int pLow = (data[6] >> 4) & 0x0F;
|
||||
int pressure = (pHigh << 4) | pLow;
|
||||
|
||||
/* 更新设备状态 */
|
||||
PenDeviceInfo info = mDeviceInfoCache.get(penMac);
|
||||
if (info != null) {
|
||||
info.lastDataTimestamp = timestamp;
|
||||
info.isWriting = true;
|
||||
}
|
||||
|
||||
/* 分发到所有监听器 */
|
||||
for (PenDataListener listener : mDataListeners) {
|
||||
listener.onStrokeData(penMac, x, y, pressure, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/** 解析设备信息特征值数据 */
|
||||
private void parseDeviceInfo(String penMac, byte[] data) {
|
||||
if (data == null || data.length < 4) return;
|
||||
|
||||
PenDeviceInfo info = mDeviceInfoCache.get(penMac);
|
||||
if (info == null) {
|
||||
info = new PenDeviceInfo();
|
||||
info.macAddress = penMac;
|
||||
mDeviceInfoCache.put(penMac, info);
|
||||
}
|
||||
|
||||
/* 第一字节:电量百分比 */
|
||||
info.batteryLevel = data[0] & 0xFF;
|
||||
|
||||
/* 第2-4字节:固件版本 major.minor.patch */
|
||||
info.firmwareVersion = (data[1] & 0xFF) + "." + (data[2] & 0xFF)
|
||||
+ "." + (data[3] & 0xFF);
|
||||
|
||||
/* 通知电量更新 */
|
||||
for (PenConnectionListener listener : mConnectionListeners) {
|
||||
listener.onBatteryUpdate(penMac, info.batteryLevel);
|
||||
}
|
||||
|
||||
Log.i(TAG, "设备信息 [" + penMac + "] 电量:" + info.batteryLevel
|
||||
+ "% 固件:" + info.firmwareVersion);
|
||||
}
|
||||
|
||||
/* ========== 自动重连 ========== */
|
||||
|
||||
/** 安排自动重连(指数退避) */
|
||||
private void scheduleReconnect(String macAddress) {
|
||||
Integer attempts = mReconnectAttempts.getOrDefault(macAddress, 0);
|
||||
if (attempts >= 5) {
|
||||
Log.w(TAG, "设备 " + macAddress + " 重连次数已达上限,放弃重连");
|
||||
mReconnectAttempts.remove(macAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
mReconnectAttempts.put(macAddress, attempts + 1);
|
||||
|
||||
/* 指数退避:3s, 6s, 12s, 24s, 48s */
|
||||
long delay = RECONNECT_DELAY_MS * (1L << attempts);
|
||||
|
||||
mBleHandler.postDelayed(() -> {
|
||||
if (!mConnectedPens.containsKey(macAddress)) {
|
||||
Log.i(TAG, "尝试重连设备: " + macAddress + "(第" + (attempts + 1) + "次)");
|
||||
connectPen(macAddress);
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
|
||||
/* ========== 控制指令发送 ========== */
|
||||
|
||||
/**
|
||||
* 向笔发送控制指令
|
||||
* @param macAddress 目标笔MAC
|
||||
* @param command 指令字节数组
|
||||
* @return 是否发送成功
|
||||
*/
|
||||
public boolean sendCommand(String macAddress, byte[] command) {
|
||||
BluetoothGatt gatt = mConnectedPens.get(macAddress);
|
||||
if (gatt == null) {
|
||||
Log.w(TAG, "设备未连接,无法发送指令: " + macAddress);
|
||||
return false;
|
||||
}
|
||||
|
||||
BluetoothGattService service = gatt.getService(PEN_SERVICE_UUID);
|
||||
if (service == null) return false;
|
||||
|
||||
BluetoothGattCharacteristic controlChar =
|
||||
service.getCharacteristic(PEN_CONTROL_CHAR_UUID);
|
||||
if (controlChar == null) return false;
|
||||
|
||||
controlChar.setValue(command);
|
||||
controlChar.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
|
||||
return gatt.writeCharacteristic(controlChar);
|
||||
}
|
||||
|
||||
/** 查询笔电量 */
|
||||
public int getBatteryLevel(String macAddress) {
|
||||
PenDeviceInfo info = mDeviceInfoCache.get(macAddress);
|
||||
return info != null ? info.batteryLevel : -1;
|
||||
}
|
||||
|
||||
/* ========== 资源释放 ========== */
|
||||
|
||||
/** 释放PenManager资源 */
|
||||
public void destroy() {
|
||||
stopScan();
|
||||
disconnectAll();
|
||||
mDataListeners.clear();
|
||||
mConnectionListeners.clear();
|
||||
mDeviceInfoCache.clear();
|
||||
|
||||
if (mBleThread != null) {
|
||||
mBleThread.quitSafely();
|
||||
mBleThread = null;
|
||||
}
|
||||
Log.i(TAG, "PenManager资源已释放");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user