杰理 SDK 文档中心
首页
首页
  • 项目概述

    • 项目简介与核心能力
    • 运行环境与SDK版本
  • 快速开始

    • 工程导入与依赖配置
    • 权限配置与示例运行
  • 平台架构

    • SDK分层架构与RCSP协议
    • 蓝牙连接库
    • 健康SDK核心库 JL_Watch
    • 健康服务器与云端服务
  • 健康与运动数据

    • 健康数据同步
    • 运动数据同步
    • 本地数据持久化
  • 设备管理功能

    • 表盘管理
    • 闹钟与健康提醒
    • 消息与联系人同步
    • 天气同步
    • 设备查找
    • 支付宝集成
  • 传输与媒体处理

    • 文件传输与文件管理
    • 音乐传输与播放控制
    • 图像转换库
    • 音频编解码与解密
  • OTA 升级

    • 固件空中升级流程
    • 4G模块与差分升级
  • AI 能力

    • AI表盘与云服务
    • AI语音助手
  • 示例应用

    • HealthAide 健康助手应用
    • WatchTestTool 测试工具
  • 开发者指南

    • 自定义命令扩展
    • 调试技巧与问题排查
    • 版本历史与兼容性

AI表盘与云服务

AI表盘与云服务是 HealthAide 中基于语音交互与云端大模型(科大讯飞星火 SparkChain)实现"一句话生成表盘"及"健康云服务问答"的完整能力链路,涵盖语音识别(IAT)、语义理解、文生图、表盘图像处理、RCSP 协议传输安装与云消息本地持久化。

Purpose and Scope

本页面向该能力的端到端实现,从用户语音输入到表盘在手表上安装完成,以及 AI 云服务消息的收发与持久化:

  • AI 能力入口与供应商抽象(AIManager、AISupplier)
  • 语音识别链路(IAT)与 AI 对话/文生图链路(讯飞星火 SparkChain)
  • AI 表盘处理与传输(AIDialWrapper:图像裁剪缩放、BmpConvert 格式转换、FAT FS 传输、表盘安装)
  • AI 云服务(AICloudServeWrapper)与云消息本地存储(AICloudMessageEntity / AICloudMessageDao)
  • 配置(aiui_phone.cfg、SparkChain AAR)与失败处理

以下内容不属于本页范围,将在对应目录页中介绍:通用蓝牙协议栈(RCSP)、自定义表盘管理(CustomDialManager)、WatchManager 设备管理。本页仅说明 AI 能力如何调用它们。

Overview

AI 表盘功能的使用场景是:用户对 App 说出"帮我生成一个星空风格的表盘",系统依次完成:

  1. 语音识别(IAT)将音频转为文本(BaseAIIatHandler / IflytekAIIatHandler);
  2. AI 对话/文生图把文本(加上当前绘画风格前缀)发送给讯飞星火大模型,生成一张表盘背景图;
  3. 图像处理与传输:把生成图裁剪缩放到手表屏幕尺寸与 240×240 缩略图,经 BmpConvert 转为芯片所需位图格式,通过 FAT FS 写入手表,并触发表盘安装;
  4. 安装与状态同步:设备端 RCSP 命令回传安装状态,App 侧 AIDialWrapper 通过 AIDialListener 驱动整个流程。

AI 云服务则是同一语音/对话框架下的另一分支(BaseAICloudServeHandler / IflytekAICloudServeHandler),用于健康问答类云服务消息,消息通过 AICloudMessageEntity 保存在本地 Room 数据库(AICloudMessageDao)。

整个能力构建在一个供应商抽象之上:AIDialWrapper 中 AISupplier = 1(0 表示杰理、1 表示科大讯飞),当前实现以科大讯飞为主。

Architecture

flowchart TD
    subgraph sg_Entry["入口层"]
        AIManager["AIManager<br/>AI能力总入口"]
    end

    subgraph sg_Handler["Handler 层(职责链抽象)"]
        BaseAIHandler["BaseAIHandler"]
        BaseAIChatHandler["BaseAIChatHandler<br/>AI对话基类"]
        BaseAIIat["BaseAIIatHandler<br/>语音识别基类"]
        BaseAIDial["BaseAIDialHandler<br/>AI表盘基类"]
        BaseACloud["BaseAICloudServeHandler<br/>云服务基类"]
        IflyAIDial["IflytekAIDialHandler<br/>讯飞表盘实现"]
        IflyACloud["IflytekAICloudServeHandler<br/>讯飞云服务实现"]
    end

    subgraph sg_SDK["云端 SDK 封装"]
        T2I["IflytekTextToImageWrapper<br/>星火文生图"]
        AIUI["AIUI / IAT 识别<br/>aiui_phone.cfg"]
        Spark["SparkChain_V2.0.1_rc1.aar"]
    end

    subgraph sg_RCSP["RCSP 封装层"]
        AIDialWrapper["AIDialWrapper<br/>AI表盘协议"]
        AICloudWrapper["AICloudServeWrapper<br/>云服务协议"]
        AIRecordWrapper["AIRecordWrapper<br/>录音封装"]
        AIDialListener["AIDialListener<br/>流程回调"]
    end

    subgraph sg_Device["设备与存储"]
        WatchManager["WatchManager"]
        BmpConvert["BmpConvert<br/>位图格式转换"]
        FATFS["FAT FS 文件系统<br/>缩略图/背景图"]
        Room["Room DB<br/>AICloudMessageEntity"]
    end

    AIManager --> BaseAIHandler
    BaseAIHandler --> BaseAIChatHandler
    BaseAIChatHandler --> BaseAIIat
    BaseAIChatHandler --> BaseAIDial
    BaseAIChatHandler --> BaseACloud
    BaseAIDial --> IflyAIDial
    BaseACloud --> IflyACloud
    IflyAIDial --> T2I
    T2I --> Spark
    BaseAIIat --> AIUI
    IflyAIDial --> AIDialWrapper
    AIDialWrapper --> AIDialListener
    AIDialWrapper --> WatchManager
    AIDialWrapper --> BmpConvert
    AIDialWrapper --> FATFS
    IflyACloud --> AICloudWrapper
    AICloudWrapper --> Room

架构说明:

  • Handler 层是核心抽象:BaseAIHandler → BaseAIChatHandler → 三个分支(IAT、AI 表盘、AI 云服务)。BaseAIDialHandler 继承 BaseAIChatHandler,因此表盘生成复用了 AI 对话的文本链路(startAIChat / retryAIChat),只在其上叠加了表盘特有的图像处理与传输逻辑。
  • RCSP 封装层屏蔽了与手表的协议细节。AIDialWrapper 是表盘能力的枢纽:既接收设备端 RCSP 命令(CMD_AI_OPERATE),也通过 AIDialListener 向 Handler 层回调"生成表盘 / 重新生成 / 安装完成"等事件。
  • 设备与存储层:WatchManager 负责连接与 FAT FS 文件传输;BmpConvert(杰理位图转换库)把通用位图转为 701N/707N/695N 等芯片 RGB/ARGB 格式;AI 云消息通过 Room 持久化。

语音链路:IAT 识别 → AI 对话

AI 表盘的入口是语音。BaseAIDialHandler 继承自 BaseAIChatHandler,因此它天然具备语音识别与 AI 对话能力,关键回调如下:

@Override
void onIatText(String iatText) {
    mIatText = iatText;
    transferIatText(mIatText);
}

@Override
void onIatStartRecord() {
    mIatText = null;
}

Source: BaseAIDialHandler.java

  • onIatText:语音识别出文本后,先保存到 mIatText,再调用 transferIatText() 把文本交给 AI 对话/云端语义理解;识别文本会被稍后用于表盘生成(onGenerateDial 时读取 mIatText)。
  • onIatStartRecord:开始录音时清空上一次的识别文本,避免把旧文本混入新一轮表盘生成。
  • 识别为空时走 onIatRecognizeEmptyError(),向 UI 抛出 R.string.ai_no_speak("没有听到说话");网络异常时 onIatNetworkError() / onTTINetworkError() 抛出 R.string.ai_network_wrong。
@Override
void onIatNetworkError() {
    String error = mContext.getString(R.string.ai_network_wrong);
    mAIDialWrapper.asyncMessageAIError(error, null);
}

Source: BaseAIDialHandler.java

设计意图:表盘生成与错误提示都通过 AIDialWrapper.asyncMessageAIError() 回传 UI,Handler 层不直接持有界面引用,保持视图与业务解耦。

AI 表盘生成(BaseAIDialHandler / IflytekAIDialHandler)

流程驱动:AIDialListener

BaseAIDialHandler 构造时向 AIDialWrapper 注册一个 AIDialListener,把设备侧/协议侧事件翻译成 AI 对话动作:

private final AIDialListener mAIDialListener = new AIDialListener() {
    @Override
    public void onGenerateDial() {
        super.onGenerateDial();
        //开始生成AI表盘
        startAIChat(mIatText);
    }

    @Override
    public void onInstallDialStart() {
        super.onInstallDialStart();
        //开始安装表盘:1.生成自定义表盘文件,2.传输表盘
    }

    @Override
    public void onReGenerateDial() {
        super.onReGenerateDial();
        //重新生成表盘
        retryAIChat();
    }
};

public BaseAIDialHandler(AIDialWrapper aiDialWrapper, WatchManager rcspOp, Context context) {
    super(rcspOp, context);
    mAIDialWrapper = aiDialWrapper;
    mAIDialWrapper.registerListener(mAIDialListener);
    testSrc = (int) (Math.random() * 9);
}

Source: BaseAIDialHandler.java

  • onGenerateDial → startAIChat(mIatText):用户确认生成后,把识别文本送入 AI 对话/文生图;
  • onReGenerateDial → retryAIChat():用户点击"重新生成",复用同一文本再跑一次;
  • onRecordingAgain 无需处理(录音重来由 IAT Handler 负责);
  • testSrc 随机数(0–8)疑似用于内部测试图片来源,生产逻辑中未看到其实际分支调用。

release() 时对称地 unregisterListener,避免内存泄漏。

文生图实现(讯飞星火)

IflytekAIDialHandler 是讯飞供应商的具体实现,核心在 onStartAIChat:

@Override
void onStartAIChat(String userText) {
    String chatText = getCurrentAIDialStyle() + userText;
    mIflytekTextToImageWrapper.execute(chatText, stateResult -> {
        if (stateResult.getState() == BasicWrapper.STATUS_FINISH) {
            if (stateResult.isSuccess()) { //生产图片成功
                final LLMResult result = stateResult.getResult();
                final byte[] imageData = result.getImage();
                String savePath = FileUtil.createFilePath(mContext, "aidial")
                        + File.separator + "aiSrc_cache";
                File file = new File(savePath);
                if (file.exists()) {
                    file.delete();
                }
                if (FileUtil.bytesToFile(imageData, savePath)) {
                    handleAIChatImage(savePath);
                } else {
                    JL_Log.w(TAG, "onStartAIChat", "Failed to save bitmap. " +
                            "data size : " + imageData.length + ", \nsave Path : " + savePath);
                    onTTINetworkError();
                }
                return;
            }
            onTTINetworkError();
        }
    });
}

Source: IflytekAIDialHandler.java

要点:

  • 提示词拼接:chatText = getCurrentAIDialStyle() + userText,把当前绘画风格(如"卡通/水彩/油画")作为前缀拼进用户文本,让大模型按风格生成;
  • 同步停止:IflytekAIDialHandler 注册了 OnWatchCallback,当目标设备断连或连接失败(CONNECTION_DISCONNECT / CONNECTION_FAILED)时调用 mIflytekTextToImageWrapper.stop(),避免设备不在线时继续消耗云端算力;
  • 结果落盘:LLMResult.getImage() 拿到图片字节流,写入 aidial/aiSrc_cache 文件,成功后再交给 handleAIChatImage() 进入表盘图像处理管线;写盘失败或生成失败统一走 onTTINetworkError()。

getCurrentAIDialStyle() / setCurrentAIDialStyle(String) 透传 AIDialWrapper 的 getPainStyle() / setPaintStyle(),绘画风格是全局状态,由 MSG_SET_PAIN_STYLE 消息在设备初始化后同步给手表(见下节)。

表盘图像处理与传输(AIDialWrapper)

AIDialWrapper(com.jieli.healthaide.tool.aiui.rcsp)是表盘能力的协议枢纽,头部常量定义了整套传输约定:

private final int AISupplier = 1;//ai供应商,0:杰理,1:科大讯飞
private final String THUMB_PATH = "/AITHUMB";
private final static String WATCH_PREFIX = "WATCH";
private final static String CUSTOM_BG_PREFIX = "bgp_w";
private final static String JPG_FORMAT = ".jpg";
private final LinkedBlockingQueue<SendTaskParam> mSendTaskQueue = new LinkedBlockingQueue<>();
private final int MSG_SET_PAIN_STYLE = 101;
private int thumbWidth = 240;
private int thumbHeight = 240;

Source: AIDialWrapper.java

图片裁剪与缩略图生成:handleNlpImage

AI 对话返回图片后,handleNlpImage() 负责生成"待安装背景图"和"240×240 缩略图":

public void handleNlpImage(String srcPath, String tempThumbPath, String tempDialPath) {
    if (!mWatchManager.isConnected()) return;
    File tempThumbFile = new File(tempThumbPath);
    if (tempThumbFile.exists()) tempThumbFile.delete();
    File tempDialFile = new File(tempDialPath);
    if (tempDialFile.exists()) tempDialFile.delete();
    dialImagePath = tempDialPath;
    AppUtil.copyFile(srcPath, tempDialPath);
    AppUtil.copyFile(srcPath, tempThumbPath);
    Bitmap thumb = HealthUtil.createScaleBitmap(tempThumbPath, thumbWidth, thumbHeight);
    thumb = getCropBitmap(thumb);
    BitmapUtil.bitmapToFile(thumb, tempThumbPath, 100);
    thumb.recycle();
    transferThumb(tempThumbPath);
}

Source: AIDialWrapper.java

  • 未连接手表时直接返回(if (!mWatchManager.isConnected()) return;),避免无意义的文件操作;
  • 生成图先复制两份:tempDialPath(背景图原样保留,后续安装用)与 tempThumbPath(缩放 240×240 再裁剪);
  • transferThumb() 先传缩略图给手表,让用户在生成背景图期间就能看到预览效果;
  • 文件被注释掉的旧版实现展示了更精细的"按手表宽高等比缩放居中裁剪"算法(scale = Math.min(widthScale, heightScale)、offsetX/offsetY 补偿),可作为后续优化参考。

位图格式转换与传输:transferThumb

public void transferThumb(String thumbFilePath) {
    DeviceInfo deviceInfo = mWatchManager.getDeviceInfo(mWatchManager.getConnectedDevice());
    if (deviceInfo == null) return;
    onTransferThumbStart();
    int type;
    WatchConfigure watchConfigure = mWatchManager.getWatchConfigure(mWatchManager.getConnectedDevice());
    switch (deviceInfo.getSdkType()) {
        case JLChipFlag.JL_CHIP_FLAG_701X_WATCH:
            type = BmpConvert.TYPE_701N_RGB;
            if (watchConfigure != null && watchConfigure.getFunctionOption().isSupportDialExpandInfo()) {
                type = BmpConvert.TYPE_701N_ARGB;
            }
            break;
        case JLChipFlag.JL_CHIP_FLAG_707N_WATCH:
            type = BmpConvert.TYPE_707N_RGB;
            if (watchConfigure != null && watchConfigure.getFunctionOption().isSupportDialExpandInfo()) {
                type = BmpConvert.TYPE_707N_ARGB;
            }
            break;
        default:
            type = BmpConvert.TYPE_695N_RBG;
            break;
    }
    String outPath = getOutPath(thumbFilePath);
    mBmpConvert.bitmapConvert(type, thumbFilePath, outPath, new OnConvertListener() {
        @Override
        public void onStop(boolean result, String s) {
            if (result) {
                mWatchManager.addFatFile(s, true, new OnFatFileProgressListener() { ... });
            }
        }
    });
}

Source: AIDialWrapper.java

设计要点:

  • 按芯片型号选格式:701X/707N 系列支持 RGB 与 ARGB 两种位图格式,是否启用 ARGB 取决于设备配置 WatchConfigure.functionOption.isSupportDialExpandInfo()(是否支持表盘扩展信息);默认 695N 走 TYPE_695N_RBG;
  • FAT FS 写入:bitmapConvert 转换成功后通过 mWatchManager.addFatFile() 把文件写入手表文件系统,并带进度监听 OnFatFileProgressListener;
  • 串行发送队列:LinkedBlockingQueue<SendTaskParam> mSendTaskQueue 配合 volatile boolean isSendData 保证多个发送任务(缩略图/背景图/风格同步)按序执行,避免并发写文件系统导致冲突;
  • 风格同步:mUIHandler 收到 MSG_SET_PAIN_STYLE(设备 onWatchSystemInit 后延迟 1 秒触发)时,先校验 isSupportAIDial(),再调用 notifyDevPaintStyle(mPainStyle) 把当前绘画风格下发给手表;
  • 设备事件:onRcspCommand 监听 CMD_AI_OPERATE 且 AI_OP_AI_DIAL 的命令,其中 AI_DIAL_OP_UI 标志携带 scaleZoomWidth/Height,用于设备端表盘 UI 的缩放状态同步;
  • 文件命名约定:缩略图固定为 AITHUMB.jpg(THUMB_PATH.replaceAll(File.separator, "") + JPG_FORMAT),背景图用 bgp_w + 序号 + .jpg(CUSTOM_BG_PREFIX),配合 WATCH_PREFIX 体系在手表端识别文件归属。

AI 云服务(AICloudServeWrapper / BaseAICloudServeHandler)

AI 云服务是与表盘并列的另一条 AI 能力线,目录结构如下:

  • handle/BaseAICloudServeHandler.java、handle/IflytekAICloudServeHandler.java:云服务 Handler,继承 BaseAIChatHandler,复用语音识别与 AI 对话管线,输出健康云服务消息;
  • rcsp/AICloudServeWrapper.java、rcsp/AICloudServeWrapperListener.java:与手表侧云服务功能交互的 RCSP 封装及监听器;
  • data/entity/AICloudMessageEntity.java、data/dao/AICloudMessageDao.java:云服务消息的 Room 实体与 DAO,实现本地持久化,支持历史消息查询与展示。

说明:受本次文档探索预算限制,上述云服务类与 DAO 的具体字段、方法签名未逐一展开阅读;更详细的实现请直接查阅对应源文件。表盘与云服务共用同一套"Handler 抽象 + RCSP Wrapper + 监听器"骨架,理解本页的 AIDialWrapper 结构即可快速迁移到云服务分支。

配置与资源

资源位置作用
aiui_phone.cfgapp/src/main/assets/cfg/AIUI 语音识别引擎的 App 端配置文件
SparkChain_V2.0.1_rc1.aarapp/libs/讯飞星火大模型 SDK(文生图/对话能力来源)
AISupplier = 1AIDialWrapper 字段供应商开关:0=杰理,1=科大讯飞

Core Flow:从一句话到表盘安装

sequenceDiagram
    participant U as 用户
    participant IAT as BaseAIIatHandler<br/>(讯飞IAT)
    participant D as BaseAIDialHandler
    participant T2I as IflytekTextToImageWrapper<br/>(星火文生图)
    participant W as AIDialWrapper
    participant BC as BmpConvert
    participant WM as WatchManager / FAT FS
    participant WD as 手表

    U->>IAT: 说出"星空风格表盘"
    IAT-->>D: onIatText(文本) / transferIatText
    D-->>W: 用户确认生成
    W-->>D: onGenerateDial()
    D->>D: startAIChat(mIatText)
    D->>T2I: execute(风格前缀 + 文本)
    T2I-->>D: STATUS_FINISH / image bytes
    D->>D: 保存 aiSrc_cache 图片
    D->>W: handleAIChatImage / handleNlpImage
    W->>W: 缩放240x240 + 裁剪缩略图
    W->>BC: bitmapConvert(芯片RGB/ARGB)
    BC-->>W: 转换完成
    W->>WM: addFatFile(缩略图, 进度监听)
    WM->>WD: FAT FS 写入 AITHUMB.jpg
    WD-->>W: onTransferThumbFinish
    W-->>D: onInstallDialStart
    W->>WM: 生成并传输自定义表盘文件
    WD-->>W: onInstallDialFinish(是否成功)
    D-->>W: 失败→asyncMessageAIError<br/>成功→流程结束

步骤拆解(对应真实代码):

  1. 识别:BaseAIIatHandler 完成语音识别,BaseAIDialHandler.onIatText() 保存文本并调用 transferIatText()(BaseAIDialHandler.java#L109-L113);
  2. 确认生成:用户触发生成后,AIDialWrapper 通过 AIDialListener.onGenerateDial() 回调,Handler 调用 startAIChat(mIatText)(BaseAIDialHandler.java#L28-L32);
  3. 文生图:IflytekAIDialHandler.onStartAIChat() 拼接绘画风格前缀后调用 IflytekTextToImageWrapper.execute(),成功则落盘图片字节并调用 handleAIChatImage()(IflytekAIDialHandler.java#L55-L81);
  4. 图像处理:AIDialWrapper.handleNlpImage() 生成背景图副本与 240×240 缩略图,调用 transferThumb()(AIDialWrapper.java#L254-L271);
  5. 格式转换:transferThumb() 按芯片型号(701N/707N/695N)选择 BmpConvert.TYPE_*,转换成功后 addFatFile 写入手表(AIDialWrapper.java#L326-L370);
  6. 安装:缩略图传输完成后进入安装阶段(onInstallDialStart),背景图按同样管线传输,最终 onInstallDialFinish(isSuccess) 回调 Handler;任一步失败均由 asyncMessageAIError() 提示用户。

Usage Examples

1. 注册表盘流程监听(Handler 侧)

private final AIDialListener mAIDialListener = new AIDialListener() {
    @Override
    public void onGenerateDial() {
        super.onGenerateDial();
        startAIChat(mIatText);          // 用识别文本生成表盘
    }

    @Override
    public void onReGenerateDial() {
        super.onReGenerateDial();
        retryAIChat();                  // 重新生成
    }
};

public BaseAIDialHandler(AIDialWrapper aiDialWrapper, WatchManager rcspOp, Context context) {
    super(rcspOp, context);
    mAIDialWrapper = aiDialWrapper;
    mAIDialWrapper.registerListener(mAIDialListener);
}

@Override
public void release() {
    super.release();
    mAIDialWrapper.unregisterListener(mAIDialListener);
}

Source: BaseAIDialHandler.java

2. 讯飞文生图并落盘(供应商实现)

@Override
void onStartAIChat(String userText) {
    String chatText = getCurrentAIDialStyle() + userText;   // 风格 + 用户描述
    mIflytekTextToImageWrapper.execute(chatText, stateResult -> {
        if (stateResult.getState() == BasicWrapper.STATUS_FINISH) {
            if (stateResult.isSuccess()) {
                final byte[] imageData = stateResult.getResult().getImage();
                String savePath = FileUtil.createFilePath(mContext, "aidial")
                        + File.separator + "aiSrc_cache";
                if (FileUtil.bytesToFile(imageData, savePath)) {
                    handleAIChatImage(savePath);            // 进入表盘图像管线
                } else {
                    onTTINetworkError();
                }
                return;
            }
            onTTINetworkError();
        }
    });
}

Source: IflytekAIDialHandler.java

3. 缩略图裁剪与传输(Wrapper 侧)

public void handleNlpImage(String srcPath, String tempThumbPath, String tempDialPath) {
    if (!mWatchManager.isConnected()) return;
    dialImagePath = tempDialPath;
    AppUtil.copyFile(srcPath, tempDialPath);
    AppUtil.copyFile(srcPath, tempThumbPath);
    Bitmap thumb = HealthUtil.createScaleBitmap(tempThumbPath, thumbWidth, thumbHeight);
    thumb = getCropBitmap(thumb);
    BitmapUtil.bitmapToFile(thumb, tempThumbPath, 100);
    thumb.recycle();
    transferThumb(tempThumbPath);
}

Source: AIDialWrapper.java

4. 按芯片型号选择位图格式

switch (deviceInfo.getSdkType()) {
    case JLChipFlag.JL_CHIP_FLAG_701X_WATCH:
        type = BmpConvert.TYPE_701N_RGB;
        if (watchConfigure != null && watchConfigure.getFunctionOption().isSupportDialExpandInfo()) {
            type = BmpConvert.TYPE_701N_ARGB;   // 支持表盘扩展信息时启用 ARGB
        }
        break;
    case JLChipFlag.JL_CHIP_FLAG_707N_WATCH:
        type = BmpConvert.TYPE_707N_RGB;
        if (watchConfigure != null && watchConfigure.getFunctionOption().isSupportDialExpandInfo()) {
            type = BmpConvert.TYPE_707N_ARGB;
        }
        break;
    default:
        type = BmpConvert.TYPE_695N_RBG;
        break;
}

Source: AIDialWrapper.java

Configuration Options

AI 表盘能力的可配置项主要散布在 AIDialWrapper 常量与基类字段中:

配置项类型默认值说明
AISupplierint1AI 供应商开关:0=杰理,1=科大讯飞
thumbWidth / thumbHeightint240 / 240缩略图目标尺寸(缩放后裁剪)
THUMB_PATHString"/AITHUMB"手表端缩略图存放路径
WATCH_PREFIXString"WATCH"手表文件前缀标识
CUSTOM_BG_PREFIXString"bgp_w"自定义背景图文件名前缀
JPG_FORMATString".jpg"图像文件格式后缀
MSG_SET_PAIN_STYLEint101主线程 Handler 消息码:同步绘画风格
风格同步延迟long1000msonWatchSystemInit 后延迟 1 秒下发风格
资源字符串stringai_network_wrong / ai_no_speak网络错误 / 未识别到语音的提示文案

API Reference

BaseAIDialHandler(com.jieli.healthaide.tool.aiui.handle)

抽象类,继承 BaseAIChatHandler,封装 AI 表盘的公共流程。

构造: BaseAIDialHandler(AIDialWrapper aiDialWrapper, WatchManager rcspOp, Context context)

方法:

  • getCurrentAIDialStyle(): String — 获取当前绘画风格(透传 AIDialWrapper.getPainStyle())
  • setCurrentAIDialStyle(String paintStyle) — 设置绘画风格(透传 setPaintStyle(),作为文生图提示词前缀)
  • onTTINetworkError() / onIatNetworkError() — 网络异常时通过 asyncMessageAIError(R.string.ai_network_wrong) 提示 UI
  • onIatRecognizeEmptyError() — 未识别到语音时提示 R.string.ai_no_speak
  • onIatText(String iatText) — 保存识别文本并交给 AI 对话
  • onIatStartRecord() — 开始录音时清空识别文本
  • release() — 注销监听、释放资源

Throws(业务错误路径): 不抛 Java 异常;所有失败统一回调 AIDialWrapper.asyncMessageAIError(String error, Object extra)。

IflytekAIDialHandler(com.jieli.healthaide.tool.aiui.handle)

BaseAIDialHandler 的科大讯飞实现。

构造: IflytekAIDialHandler(AIDialWrapper aiDialWrapper, WatchManager rcspOp, Context context) — 创建 IflytekTextToImageWrapper,注册设备连接状态回调。

方法:

  • onStartAIChat(String userText) — 拼接风格前缀后调用星火文生图;STATUS_FINISH 且成功后保存图片字节并调用 handleAIChatImage(savePath),失败走 onTTINetworkError()
  • release() — 注销设备回调并释放上层资源

行为: 设备断连/连接失败时自动 stop() 文生图任务。

AIDialWrapper(com.jieli.healthaide.tool.aiui.rcsp)

RCSP 协议封装,负责表盘全流程的设备交互。

关键方法:

  • registerListener(AIDialListener) / unregisterListener(AIDialListener) — 注册/注销流程回调
  • handleNlpImage(String srcPath, String tempThumbPath, String tempDialPath) — 生成背景图副本与缩略图并触发传输;未连接时直接返回
  • transferThumb(String thumbFilePath) — 按芯片型号做 BmpConvert 转换后 addFatFile 写入手表
  • getThumbName(): String — 返回 AITHUMB.jpg(缩略图文件名)
  • getCustomBgName(int seq): String — 返回 bgp_w + seq + .jpg(背景图文件名)
  • getPainStyle() / setPaintStyle(String) — 绘画风格读写
  • asyncMessageAIError(String error, Object extra) — 向 UI 异步投递错误消息

设备回调(内部):

  • onWatchSystemInit(int code) — 设备系统初始化后延迟 1s 同步绘画风格(需 isSupportAIDial())
  • onRcspCommand(device, command) — 处理 CMD_AI_OPERATE 中 AI_OP_AI_DIAL 的 AI_DIAL_OP_UI 事件,携带 scaleZoomWidth/Height 缩放状态

AIDialListener(com.jieli.healthaide.tool.aiui.rcsp)

表盘流程回调接口,全部方法带空实现(super 可调用),子类按需覆写:

  • onGenerateDial() — 开始生成 AI 表盘
  • onReGenerateDial() — 重新生成表盘
  • onRecordingAgain() — 重新录音(默认不处理)
  • onTransferThumbStart() / onTransferThumbFinish(boolean isSuccess) — 缩略图传输起止
  • onInstallDialStart() / onInstallDialFinish(boolean isSuccess) — 表盘安装起止

Failure Modes、边界情况与并发

错误处理路径

场景处理方式源码位置
AI 对话/文生图网络异常onTTINetworkError() → asyncMessageAIError(R.string.ai_network_wrong)BaseAIDialHandler.java#L92-L101
IAT 识别为空onIatRecognizeEmptyError() → ai_no_speak 提示BaseAIDialHandler.java#L103-L107
生成图写盘失败日志警告 + onTTINetworkError()IflytekAIDialHandler.java#L69-L75
手表未连接handleNlpImage 直接 return,跳过图像处理AIDialWrapper.java#L255
设备信息为空transferThumb 直接 returnAIDialWrapper.java#L328-L331
设备断连/连接失败IflytekAIDialHandler 停止文生图任务IflytekAIDialHandler.java#L28-L41

边界情况

  • 设备不支持 AI 表盘:MSG_SET_PAIN_STYLE 处理时先校验 configure.getFunctionOption().isSupportAIDial(),不支持则跳过风格下发,避免向旧固件发送无效命令;
  • 表盘扩展信息差异:同一芯片(701N/707N)下是否使用 ARGB 取决于 isSupportDialExpandInfo(),必须按设备能力动态选择位图格式,否则可能花屏或无法显示;
  • 旧文本串扰:onIatStartRecord() 清空 mIatText,保证"上一轮文本"不会污染新一轮生成;
  • 临时文件残留:handleNlpImage 对 tempThumbPath/tempDialPath 先删后写,避免旧图残留导致安装错误图片。

并发与一致性

  • 串行发送队列:mSendTaskQueue(LinkedBlockingQueue)配合 volatile isSendData 保证缩略图、背景图、风格同步等 FAT FS 写操作严格串行,防止并发写文件系统破坏手表端数据一致性;
  • 主线程约束:mUIHandler 绑定主线程 Looper,MSG_SET_PAIN_STYLE 在 UI 线程执行,规避跨线程访问 WatchManager 状态的风险;
  • 生命周期对称:BaseAIDialHandler 构造注册 AIDialListener,release() 注销;IflytekAIDialHandler 同样对称注册/注销 OnWatchCallback,防止回调泄漏导致的内存问题。

Performance 与运维考量

  • 缩略图先行:先传 240×240 缩略图(体积小、转换快),用户在背景图生成/传输期间即可看到预览,缩短感知等待时间;
  • 位图转换成本:BmpConvert 按芯片格式转换是 CPU 密集型操作,转换结果写入临时文件后通过 FAT FS 传输,避免大 Bitmap 常驻内存(生成后及时 recycle());
  • 云端成本控制:断连即 stop() 文生图,避免无效请求消耗讯飞星火配额;文生图为异步回调(STATUS_FINISH),不阻塞主线程;
  • 日志可观测:关键路径均使用 JL_Log.d/w 输出(如 transferThumb 的文件路径与转换结果),线上问题可按 TAG 定位;
  • 网络依赖:IAT、文生图全部依赖云端,弱网环境下 ai_network_wrong 提示会频繁出现,需要 App 层做好网络状态引导。

Extension Points

  1. 新增 AI 供应商:AIDialWrapper.AISupplier 已预留供应商枚举(0=杰理,1=科大讯飞)。仿照 IflytekAIDialHandler 实现一个新的 BaseAIDialHandler 子类,替换文生图执行器(如杰理自研模型),即可接入新供应商而不改动 Handler 骨架与 AIDialWrapper 协议层。
  2. 扩展表盘流程回调:AIDialListener 的方法均带空实现,可在不破坏现有子类的情况下新增回调(如进度百分比回调),AIDialWrapper 在对应时机调用即可。
  3. 绘画风格体系:getPainStyle()/setPaintStyle() 是开放字符串状态,IflytekAIDialStyleHelper(tool.aiui.iflytek 包)提供风格辅助;新增风格只需扩展风格枚举与提示词映射。
  4. 云服务复用:BaseAICloudServeHandler 与 AIDialWrapper 共用 BaseAIChatHandler 管线,新的 AI 业务(如健康建议、运动报告)可按同一模式扩展 Handler + Wrapper + Listener 三件套,并用 AICloudMessageEntity 持久化。

Tests

本次探索未在源码中发现针对 aiui 包(AI 表盘/云服务)的专门测试文件;该模块高度依赖蓝牙设备与云端 SDK,测试覆盖主要体现在设备真机联调与协议回调验证上。建议的测试策略:对 handleNlpImage 的缩放裁剪算法做纯本地单元测试,对 transferThumb 的 BmpConvert 类型选择做参数化测试(701N/707N/695N × RGB/ARGB),对 AIDialListener 回调编排做 Mock 测试。

Related Links

  • AIManager.java(AI 能力总入口)
  • BaseAIDialHandler.java
  • IflytekAIDialHandler.java
  • AIDialWrapper.java
  • AIDialListener.java
  • BaseAICloudServeHandler.java / IflytekAICloudServeHandler.java
  • AICloudServeWrapper.java
  • AICloudMessageEntity.java(云消息持久化实体)
  • AICloudMessageDao.java
  • aiui_phone.cfg(AIUI 识别配置)
  • IflytekAIDialStyleHelper.java(绘画风格辅助)

相关目录页:AI 语音识别(IAT)细节、AI 对话(Chat)细节见 8-ai-capabilities 目录下对应子页;手表协议与文件系统传输的通用机制见 WatchManager / 自定义表盘相关页面。

Next
AI语音助手