Initial Android project setup with Compose, WebSocket, and VoiceInteractionService
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
# 00 — 项目概述与架构
|
||||
|
||||
> 对应主项目 Phase 5(v1.5 → v2.0)Android 客户端
|
||||
> 主项目文档:`../../docs/dev-plan/04-voice-system-plan.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. 项目定位
|
||||
|
||||
Cyrene for Android 是昔涟的官方 Android 客户端,定位为 **可替换系统自带语音助手的智能体 APP**(替代 Google Assistant / Bixby)。
|
||||
|
||||
核心差异点:
|
||||
- 不是传统 APP(以桌面图标为主要入口),而是**系统级语音助手**
|
||||
- 除常规全屏 Activity 外,通过 `VoiceInteractionSession` 提供悬浮式覆盖层交互
|
||||
- 支持息屏热词唤醒、长按 Home / 电源键呼出
|
||||
|
||||
## 2. 技术栈
|
||||
|
||||
| 层 | 技术 | 版本要求 |
|
||||
|----|------|---------|
|
||||
| 语言 | Kotlin | 2.0+ |
|
||||
| UI 框架 | Jetpack Compose + Material Design 3 | BOM 2025+ |
|
||||
| 构建 | Gradle (Kotlin DSL) | 8.7+ |
|
||||
| 架构模式 | MVVM + Repository | — |
|
||||
| 依赖注入 | Hilt / Koin (待定) | — |
|
||||
| 网络 | Retrofit + OkHttp | — |
|
||||
| 实时通信 | OkHttp WebSocket | — |
|
||||
| 本地存储 | Room (SQLite) + DataStore | — |
|
||||
| 推送 | FCM (Firebase Cloud Messaging) | — |
|
||||
| 系统语音 | VoiceInteractionService | API 23+ |
|
||||
| 热词唤醒 | Always-On Hotword Detection | API 23+ |
|
||||
| 语音识别 | 服务端 (Whisper API) + 本地兜底 | — |
|
||||
|
||||
## 3. 最低系统要求
|
||||
|
||||
| 项目 | 要求 |
|
||||
|------|------|
|
||||
| minSdk | 26 (Android 8.0) |
|
||||
| targetSdk | 35+ |
|
||||
| compileSdk | 35+ |
|
||||
| JDK | 17 |
|
||||
| Gradle | 8.7+ |
|
||||
|
||||
注:`VoiceInteractionService` 基础 API 要求 23,`AssistAction` 热词唤醒要求 23。minSdk 设为 26 以覆盖绝大多数活跃设备并简化兼容性。
|
||||
|
||||
## 4. 项目结构
|
||||
|
||||
```
|
||||
android/
|
||||
├── app/
|
||||
│ ├── src/main/
|
||||
│ │ ├── java/com/cyrene/app/
|
||||
│ │ │ ├── CyreneApplication.kt # Application 初始化
|
||||
│ │ │ ├── MainActivity.kt # 全屏主界面 (桌面图标入口)
|
||||
│ │ │ ├── ui/
|
||||
│ │ │ │ ├── theme/ # MD3 主题 (Color / Type / Shape)
|
||||
│ │ │ │ ├── screens/ # 全屏页面 (Compose)
|
||||
│ │ │ │ │ ├── chat/ # 对话页
|
||||
│ │ │ │ │ ├── home/ # 首页 / IoT 面板
|
||||
│ │ │ │ │ ├── settings/ # 设置页
|
||||
│ │ │ │ │ └── login/ # 登录/注册
|
||||
│ │ │ │ ├── overlay/ # 悬浮窗对话界面 (VoiceInteractionSession)
|
||||
│ │ │ │ └── components/ # 共享组件库
|
||||
│ │ │ ├── viewmodel/ # ViewModel 层
|
||||
│ │ │ ├── domain/ # 领域层 (UseCase / Repository 接口)
|
||||
│ │ │ ├── data/
|
||||
│ │ │ │ ├── remote/ # API 接口定义 + DTO
|
||||
│ │ │ │ ├── local/ # Room DAO + DataStore
|
||||
│ │ │ │ └── repository/ # Repository 实现
|
||||
│ │ │ ├── service/
|
||||
│ │ │ │ ├── CyreneVoiceInteractionService.kt
|
||||
│ │ │ │ ├── CyreneVoiceInteractionSession.kt
|
||||
│ │ │ │ ├── CyreneAssistService.kt
|
||||
│ │ │ │ └── WebSocketService.kt
|
||||
│ │ │ ├── voice/
|
||||
│ │ │ │ ├── hotword/ # 热词唤醒引擎
|
||||
│ │ │ │ ├── stt/ # 语音识别客户端
|
||||
│ │ │ │ └── tts/ # 语音合成客户端
|
||||
│ │ │ ├── di/ # DI 模块定义
|
||||
│ │ │ └── util/ # 工具类
|
||||
│ │ ├── res/ # 资源文件
|
||||
│ │ └── AndroidManifest.xml
|
||||
│ └── build.gradle.kts
|
||||
├── gradle/
|
||||
│ ├── libs.versions.toml # 版本目录
|
||||
│ └── wrapper/
|
||||
├── build.gradle.kts # 根构建脚本
|
||||
├── settings.gradle.kts
|
||||
└── gradle.properties
|
||||
```
|
||||
|
||||
## 5. 架构分层
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────┐
|
||||
│ UI Layer (Compose) │
|
||||
│ ├─ Screens (全屏 Activity) │
|
||||
│ └─ Overlay (VoiceInteractionSession 悬浮窗) │
|
||||
├──────────────────────────────────────────────┤
|
||||
│ ViewModel Layer │
|
||||
│ ├─ ChatViewModel │
|
||||
│ ├─ HomeViewModel (IoT) │
|
||||
│ ├─ SettingsViewModel │
|
||||
│ └─ OverlayViewModel │
|
||||
├──────────────────────────────────────────────┤
|
||||
│ Domain Layer │
|
||||
│ ├─ UseCase (SendMessage, ControlIoT, ...) │
|
||||
│ └─ Repository Interfaces │
|
||||
├──────────────────────────────────────────────┤
|
||||
│ Data Layer │
|
||||
│ ├─ Remote: Retrofit API + WebSocket │
|
||||
│ ├─ Local: Room + DataStore │
|
||||
│ └─ Repository Implementation │
|
||||
├──────────────────────────────────────────────┤
|
||||
│ Service Layer │
|
||||
│ ├─ VoiceInteractionService (系统助手) │
|
||||
│ ├─ WebSocketService (长连接) │
|
||||
│ └─ FCMMessagingService (推送) │
|
||||
└──────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
UI 层和 Service 层通过 ViewModel 解耦——全屏 Activity 和悬浮窗 Overlay 复用同一组 ViewModel,只是 UI 布局不同。
|
||||
|
||||
## 6. 与后端的关系
|
||||
|
||||
```
|
||||
Android Client
|
||||
│
|
||||
├─ HTTP REST ──────────► Gateway (:8080) # 登录、CRUD、配置
|
||||
├─ WebSocket ──────────► Gateway (:8080) # 实时对话、IoT 状态推送
|
||||
├─ STT Audio ──────────► Voice Service (:8093) # 语音识别
|
||||
└─ TTS Stream ◄──────── Voice Service (:8093) # 语音合成
|
||||
```
|
||||
|
||||
WebSocket 长连接是核心通信通道:对话消息、通知、IoT 状态广播均通过同一连接。HTTP 仅用于一次性操作(登录、文件上传/下载)。
|
||||
|
||||
## 7. 关键设计决策
|
||||
|
||||
| 决策 | 选择 | 理由 |
|
||||
|------|------|------|
|
||||
| UI 框架 | Jetpack Compose + MD3 | 声明式 UI,与悬浮窗的 ComposeView 集成简单 |
|
||||
| 架构 | MVVM + Repository | Google 官方推荐,ViewModel 可在 Activity 和 Session 间复用 |
|
||||
| 语音框架 | VoiceInteractionService(系统 API) | 原生支持替换系统助手,无需自定义悬浮窗权限 |
|
||||
| 热词方案 | 系统 Always-On Hotword API | 息屏低功耗监听,不用自建音频采集 |
|
||||
| 网络 | OkHttp WebSocket | 比 FCM 更实时,与主项目 Gateway 已有 WS Hub 对应 |
|
||||
| 最低 API | 26 | 覆盖 95%+ 活跃设备,VoiceInteractionService 兼容 |
|
||||
|
||||
## 8. 排期参考
|
||||
|
||||
对应主项目路线图:
|
||||
|
||||
```
|
||||
2026 Q4 ─ v1.3 多平台接入(前置依赖)
|
||||
2027 Q1 ─ v1.8 语音模型训练完成(后端依赖)
|
||||
2027 Q2 ─ v2.0 开始 Android 客户端开发
|
||||
2027 Q3 ─ v2.3 语音助手 APP MVP 版本
|
||||
2027 Q4 ─ v3.0 APP 上架(Google Play / 国内应用商店)
|
||||
```
|
||||
@@ -0,0 +1,256 @@
|
||||
# 01 — 系统语音助手集成规范
|
||||
|
||||
> **目标**:让昔涟成为 Android 系统级默认语音助手,替换 Google Assistant / Bixby
|
||||
> **核心 API**:`VoiceInteractionService` + `VoiceInteractionSession`
|
||||
|
||||
---
|
||||
|
||||
## 1. 功能目标
|
||||
|
||||
- 用户可在 **系统设置 → 默认应用 → 数字助理** 中选择昔涟
|
||||
- 长按 Home 键呼出昔涟(非全屏,悬浮覆盖层)
|
||||
- 屏幕底部两角向内滑动触发昔涟
|
||||
- 长按电源键可配置为呼出昔涟
|
||||
- 息屏状态下热词唤醒昔涟
|
||||
- 有线/蓝牙耳机按键呼出昔涟
|
||||
|
||||
## 2. AndroidManifest.xml 声明
|
||||
|
||||
```xml
|
||||
<!-- VoiceInteractionService -->
|
||||
<service
|
||||
android:name=".service.CyreneVoiceInteractionService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_VOICE_INTERACTION">
|
||||
|
||||
<meta-data
|
||||
android:name="android.voice_interaction"
|
||||
android:resource="@xml/voice_interaction_config" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.service.voice.VoiceInteractionService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- AssistService (Android 14+) -->
|
||||
<service
|
||||
android:name=".service.CyreneAssistService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_ASSIST">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.service.voice.AssistService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
```
|
||||
|
||||
## 3. 配置文件
|
||||
|
||||
### res/xml/voice_interaction_config.xml
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<voice-interaction-service
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:sessionService=".service.CyreneVoiceInteractionSession"
|
||||
android:recognitionService=".service.CyreneRecognitionService"
|
||||
android:supportsAssist="true"
|
||||
android:supportsLaunchVoiceAssistFromKeyguard="true"
|
||||
android:supportsLocalRecognition="true"
|
||||
android:serviceIcon="@drawable/ic_cyrene"
|
||||
android:serviceLabel="@string/voice_assistant_name" />
|
||||
```
|
||||
|
||||
## 4. VoiceInteractionService 实现
|
||||
|
||||
```kotlin
|
||||
class CyreneVoiceInteractionService : VoiceInteractionService() {
|
||||
|
||||
override fun onReady() {
|
||||
super.onReady()
|
||||
// 服务就绪,可在此初始化 TTS 引擎等
|
||||
}
|
||||
|
||||
override fun onCreateSession(args: Bundle?): VoiceInteractionSession {
|
||||
return CyreneVoiceInteractionSession(this)
|
||||
}
|
||||
|
||||
override fun onLaunchVoiceAssistFromKeyguard() {
|
||||
// 锁屏启动 → 进入简化模式,仅显示对话,IoT 控制等需先解锁
|
||||
}
|
||||
|
||||
// Android 14+: AssistAction 回调
|
||||
override fun onHandleAssist(
|
||||
request: AssistRequest?,
|
||||
cancellationSignal: CancellationSignal?,
|
||||
callback: OutcomeCallback<AssistResult?>?
|
||||
) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
request?.let {
|
||||
val assistContent = it.assistContent
|
||||
// 提取当前屏幕上下文(可选,用于后续上下文感知)
|
||||
callback?.onResult(AssistResult(assistContent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. VoiceInteractionSession 实现(悬浮窗界面)
|
||||
|
||||
```kotlin
|
||||
class CyreneVoiceInteractionSession(context: Context) :
|
||||
VoiceInteractionSession(context) {
|
||||
|
||||
override fun onCreateContentView(): View {
|
||||
// 返回 ComposeView 作为悬浮窗的内容
|
||||
return ComposeView(context).apply {
|
||||
setContent {
|
||||
CyreneTheme {
|
||||
OverlayScreen(
|
||||
viewModel = overlayViewModel,
|
||||
onDismiss = { finish() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onShow(args: Bundle?, showFlags: Int) {
|
||||
super.onShow(args, showFlags)
|
||||
// 设置窗口属性:透明背景 + 底部卡片式布局
|
||||
window?.apply {
|
||||
// 半透明遮罩
|
||||
setBackgroundDrawable(ColorDrawable(0x80000000.toInt()))
|
||||
// FLAG_DIM_BEHIND 可实现模糊效果
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
addSystemGestureExclusionRects(...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onComputeInsets(outInsets: Insets?) {
|
||||
super.onComputeInsets(outInsets)
|
||||
// 控制悬浮窗内容区域
|
||||
}
|
||||
|
||||
override fun onHide() {
|
||||
super.onHide()
|
||||
// 悬浮窗隐藏时清理状态
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 关键窗口属性
|
||||
|
||||
| 属性 | 值 | 说明 |
|
||||
|------|-----|------|
|
||||
| 背景 | `ColorDrawable(0x80000000)` | 半透明黑色遮罩,透出底层 APP |
|
||||
| 内容区域 | 自适应高度 | 底部弹出,类似 Google Assistant |
|
||||
| 触摸外区域行为 | 关闭悬浮窗 | 用户点击遮罩区域关闭 |
|
||||
| 键盘弹出 | 推高内容区域 | 文本输入时自动调整 |
|
||||
|
||||
## 6. 权限清单
|
||||
|
||||
```xml
|
||||
<!-- 核心语音助手权限 -->
|
||||
<uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" />
|
||||
<uses-permission android:name="android.permission.BIND_ASSIST" />
|
||||
|
||||
<!-- 音频相关 -->
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
|
||||
<!-- 热词唤醒 -->
|
||||
<uses-permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD" />
|
||||
|
||||
<!-- 后台服务 -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
|
||||
|
||||
<!-- 网络 -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<!-- 推送 -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<!-- 锁屏交互 -->
|
||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
|
||||
```
|
||||
|
||||
## 7. 引导用户设为默认助手
|
||||
|
||||
首次启动时检测并引导:
|
||||
|
||||
```kotlin
|
||||
fun checkAndPromptDefaultAssistant(context: Context) {
|
||||
val isDefault = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val componentName = ComponentName(context, CyreneVoiceInteractionService::class.java)
|
||||
context.packageManager
|
||||
.queryIntentServices(
|
||||
Intent(VoiceInteractionService.SERVICE_INTERFACE),
|
||||
PackageManager.MATCH_DEFAULT_ONLY
|
||||
)
|
||||
.any { it.serviceInfo.packageName == context.packageName }
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
if (!isDefault) {
|
||||
// 显示引导 UI → 跳转到 Settings.ACTION_VOICE_INPUT_SETTINGS
|
||||
val intent = Intent(Settings.ACTION_VOICE_INPUT_SETTINGS)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 热词唤醒检测
|
||||
|
||||
### 方案选型
|
||||
|
||||
| 方案 | 优点 | 缺点 | 适用场景 |
|
||||
|------|------|------|---------|
|
||||
| 系统 Always-On Hotword API | 低功耗、系统级支持 | 限 Android 8+,某些 ROM 不支持 | **首选** |
|
||||
| Porcupine (Picovoice) | 跨平台、离线 | 商业许可,需额外集成 | 兜底 |
|
||||
| 自建模型 (openWakeWord) | 完全可控、低成本 | 需要本地推理能力 | 长期方案 |
|
||||
|
||||
### 唤醒词配置
|
||||
|
||||
| 优先级 | 唤醒词 | 说明 |
|
||||
|--------|--------|------|
|
||||
| P0 | "昔涟" (Xī Lián) | 角色名,默认唤醒词 |
|
||||
| P1 | "Hey 昔涟" | 与 "Hey Google" 习惯对齐 |
|
||||
| P2 | 自定义 | 用户可在设置中自定义 |
|
||||
|
||||
### 息屏唤醒流程
|
||||
|
||||
```
|
||||
用户说出唤醒词
|
||||
→ HotwordDetector 识别成功(<800ms)
|
||||
→ 系统触发 VoiceInteractionService
|
||||
→ CyreneVoiceInteractionSession.onCreateContentView()
|
||||
→ Overlay 显示,播放连接提示音
|
||||
→ 用户说话 → STT → AI-Core → TTS → 语音回复
|
||||
→ 对话结束 → finish() → 息屏
|
||||
```
|
||||
|
||||
## 9. Dismiss 时机
|
||||
|
||||
悬浮窗在以下情况关闭:
|
||||
|
||||
| 条件 | 行为 |
|
||||
|------|------|
|
||||
| 用户说"再见" / "退下" | 自然对话结束,收起悬浮窗 |
|
||||
| 用户点击遮罩区域 | 立即关闭 |
|
||||
| 对话静默 10 秒 | 自动收起 |
|
||||
| 用户主动滑动关闭 | 手势关闭,同 Google Assistant |
|
||||
| 收到系统电话等中断 | 暂停语音,进入后台等待 |
|
||||
|
||||
## 10. 降级策略
|
||||
|
||||
当系统不支持 `VoiceInteractionService` 或未设为默认助手时:
|
||||
|
||||
- **保底方案**:PWA(利用主项目已有的 PWA 支持)
|
||||
- **WebView 封装**:内嵌 H5 对话界面作为过渡
|
||||
- **通知栏常驻**:提供快速对话入口,但功能受限
|
||||
@@ -0,0 +1,237 @@
|
||||
# 02 — 交互流程与导航设计
|
||||
|
||||
> **核心原则**:间接启动(语音/手势)不进入全屏 APP,而是以悬浮覆盖层呈现
|
||||
> **关联文档**:[01-voice-assistant-system.md](01-voice-assistant-system.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 启动来源 → 界面模式 映射表
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 启动来源 │
|
||||
├───────────────────────┬──────────────────────────────────┤
|
||||
│ 直接启动 (Explicit) │ 间接启动 (Implicit) │
|
||||
├───────────────────────┼──────────────────────────────────┤
|
||||
│ · 桌面图标 │ · 语音唤醒 ("昔涟") │
|
||||
│ · 最近任务列表 │ · 长按 Home 键 │
|
||||
│ · 通知栏点击 │ · 底部两角向内滑动 │
|
||||
│ · Deep Link │ · 长按电源键 (配置后) │
|
||||
│ │ · 耳机按键 (单击/长按) │
|
||||
│ │ · 锁屏右滑助手 │
|
||||
├───────────────────────┼──────────────────────────────────┤
|
||||
│ ▼ │ ▼ │
|
||||
│ 全屏 Activity │ VoiceInteractionSession │
|
||||
│ (MainActivity) │ (全屏悬浮覆盖层) │
|
||||
│ · 完整导航栏 │ · 无导航栏 │
|
||||
│ · Tab 切换 │ · 仅对话卡片 │
|
||||
│ · 设置/IoT 面板 │ · 半透明遮罩透出底层 │
|
||||
│ · 压入返回栈 │ · 不压入返回栈 │
|
||||
└───────────────────────┴──────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 2. 全屏 Activity 模式
|
||||
|
||||
### 2.1 导航结构
|
||||
|
||||
```
|
||||
MainActivity
|
||||
├── BottomNavigation
|
||||
│ ├── Tab 1: 对话 (ChatScreen) ← 默认页
|
||||
│ ├── Tab 2: IoT 面板 (IoTScreen)
|
||||
│ └── Tab 3: 我的 (ProfileScreen)
|
||||
├── TopAppBar
|
||||
│ ├── 昔涟状态指示器 (在线/思考中/离线)
|
||||
│ └── 快捷操作 (设置、通知)
|
||||
└── 子页面 (通过 NavHost 导航)
|
||||
├── SettingsScreen
|
||||
├── MemoryScreen (记忆查看)
|
||||
├── KnowledgeScreen (知识库)
|
||||
├── AutomationScreen (自动化规则)
|
||||
├── ReminderScreen (提醒列表)
|
||||
└── LoginScreen
|
||||
```
|
||||
|
||||
### 2.2 导航图 (NavGraph)
|
||||
|
||||
```
|
||||
LoginScreen ──(登录成功)──► MainScreen (带 BottomNav)
|
||||
│
|
||||
┌────────────┼────────────┐
|
||||
▼ ▼ ▼
|
||||
ChatScreen IoTScreen ProfileScreen
|
||||
│ │
|
||||
▼ ▼
|
||||
MemoryScreen SettingsScreen
|
||||
KnowledgeScreen ├─ Account
|
||||
AutomationScreen ├─ Appearance (主题)
|
||||
ReminderScreen ├─ Voice (唤醒词/语音)
|
||||
├─ IoT Config
|
||||
└─ About
|
||||
```
|
||||
|
||||
### 2.3 登录流程
|
||||
|
||||
```
|
||||
APP 首次启动
|
||||
→ 检查本地 Token
|
||||
├─ 有效 → 直接进入 MainScreen
|
||||
└─ 无效 → LoginScreen
|
||||
├─ 输入 Gateway 地址 + 账号密码
|
||||
├─ POST /api/v1/auth/login
|
||||
├─ 保存 Token 到 DataStore
|
||||
└─ 进入 MainScreen
|
||||
```
|
||||
|
||||
## 3. 悬浮覆盖层模式 (VoiceInteractionSession)
|
||||
|
||||
### 3.1 视觉层级
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────┐
|
||||
│ 底层 APP (半透明可见) │
|
||||
│ ┌──────────────────────────────┐ │
|
||||
│ │ 半透明黑色遮罩 (80% 不透明度) │ │
|
||||
│ │ │ │
|
||||
│ │ ┌──────────────────────┐ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ 对话卡片区域 │ │ │
|
||||
│ │ │ (圆角顶部 28dp) │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ · 昔涟状态条 │ │ │
|
||||
│ │ │ · 对话消息流 │ │ │
|
||||
│ │ │ · 文本输入框 │ │ │
|
||||
│ │ │ · 语音输入按钮 │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ └──────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ └──────────────────────────────┘ │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 覆盖层生命周期
|
||||
|
||||
```
|
||||
Trigger (唤醒词/手势/按键)
|
||||
│
|
||||
▼
|
||||
VoiceInteractionSession.onCreateContentView()
|
||||
│
|
||||
▼
|
||||
onShow() → 设置窗口属性 → 播放出现动画(底部滑入)
|
||||
│
|
||||
▼
|
||||
OverlayScreen Compose 渲染
|
||||
│
|
||||
├→ 用户说话 → STT → 显示识别文本 → 发送到 AI-Core
|
||||
│ │
|
||||
│ ▼
|
||||
│ SSE 流式响应
|
||||
│ │
|
||||
├← TTS 语音播放 ←── 流式合成 ←────────────┘
|
||||
│
|
||||
├→ 用户打字输入 → WebSocket 发送 → 显示回复气泡
|
||||
│
|
||||
▼
|
||||
对话结束
|
||||
├→ 用户主动关闭 (说"再见"/点击遮罩/下滑)
|
||||
└→ 超时自动关闭 (静默 10 秒)
|
||||
│
|
||||
▼
|
||||
onHide() → 播放消失动画(底部滑出)
|
||||
│
|
||||
▼
|
||||
finish() → 返回触发前界面
|
||||
```
|
||||
|
||||
### 3.3 覆盖层状态机
|
||||
|
||||
```
|
||||
┌──────────┐
|
||||
│ IDLE │ (覆盖层不可见)
|
||||
└────┬─────┘
|
||||
│ 触发
|
||||
▼
|
||||
┌──────────┐
|
||||
│LISTENING │ (等待语音输入,波形动画)
|
||||
└────┬─────┘
|
||||
│ 检测到语音 / 用户开始打字
|
||||
▼
|
||||
┌──────────┐
|
||||
│PROCESSING│ (STT 识别中 / LLM 思考中)
|
||||
└────┬─────┘
|
||||
│ 收到回复
|
||||
▼
|
||||
┌──────────┐
|
||||
│SPEAKING │ (TTS 播放中)
|
||||
└────┬─────┘
|
||||
│ 播放完毕,等待下一轮
|
||||
▼
|
||||
┌──────────┐
|
||||
│ WAITING │ (等待用户继续或关闭)
|
||||
└────┬─────┘
|
||||
│
|
||||
┌───────┼───────┐
|
||||
│ │
|
||||
用户继续说话 10s 静默
|
||||
│ │
|
||||
▼ ▼
|
||||
LISTENING IDLE
|
||||
(覆盖层关闭)
|
||||
```
|
||||
|
||||
### 3.4 与全屏 Activity 的切换
|
||||
|
||||
```
|
||||
悬浮窗中用户点击 "打开完整 APP"
|
||||
→ finish() 关闭悬浮窗
|
||||
→ startActivity(MainActivity)
|
||||
→ 用户在全屏模式下继续操作
|
||||
|
||||
全屏 APP 中用户按 Home 返回桌面
|
||||
→ onStop() → 进入后台
|
||||
→ WebSocket 保持连接
|
||||
→ 推送/FCM 通知到达时,点击通知 → 恢复 MainActivity
|
||||
```
|
||||
|
||||
## 4. 锁屏交互
|
||||
|
||||
### 4.1 锁屏唤醒
|
||||
|
||||
```
|
||||
设备锁屏 + 息屏
|
||||
│
|
||||
├→ 说出唤醒词 "昔涟"
|
||||
│ └→ onLaunchVoiceAssistFromKeyguard()
|
||||
│ └→ 简化版覆盖层 (仅对话,无 IoT / 敏感操作)
|
||||
│
|
||||
└→ 长按电源键
|
||||
└→ 同理
|
||||
```
|
||||
|
||||
### 4.2 锁屏安全策略
|
||||
|
||||
| 操作 | 锁屏状态 | 行为 |
|
||||
|------|---------|------|
|
||||
| 查询天气/时间 | 允许 | 直接回复 |
|
||||
| 简单闲聊 | 允许 | 直接回复 |
|
||||
| IoT 查询(状态) | 允许 | 回复设备状态 |
|
||||
| IoT 控制(开关) | **禁止** | 提示"请先解锁设备" |
|
||||
| 查看记忆 | **禁止** | 提示"请先解锁设备" |
|
||||
| 修改设置 | **禁止** | 提示"请先解锁设备" |
|
||||
| 宿主命令 | **禁止** | 提示"请先解锁设备" |
|
||||
|
||||
## 5. 多窗口与分屏
|
||||
|
||||
- **分屏模式**:悬浮窗模式下不支持(本身已是覆盖层);全屏 Activity 支持分屏
|
||||
- **画中画**:语音通话场景支持画中画(PIP),显示昔涟头像 + 波形动画
|
||||
|
||||
## 6. 手势交互
|
||||
|
||||
| 手势 | 悬浮窗模式 | 全屏 Activity |
|
||||
|------|-----------|---------------|
|
||||
| 下滑覆盖层 | 关闭悬浮窗 | — |
|
||||
| 点击遮罩区域 | 关闭悬浮窗 | — |
|
||||
| 长按消息 | 复制/分享菜单 | 复制/分享/删除 |
|
||||
| 左滑消息 | — | 查看消息详情/时间戳 |
|
||||
| 双击昔涟头像 | 切换输入模式(语音↔文字) | 同左 |
|
||||
@@ -0,0 +1,208 @@
|
||||
# 03 — 设计系统规范 (Material Design 3)
|
||||
|
||||
> **设计语言**:Material Design 3 (Material You)
|
||||
> **组件库**:`androidx.compose.material3`
|
||||
> **最低 API**:26(不支持 Monet 的设备回退为手动主题色)
|
||||
|
||||
---
|
||||
|
||||
## 1. 色彩系统
|
||||
|
||||
### 1.1 动态配色 (Dynamic Color)
|
||||
|
||||
```
|
||||
首选:androidx.compose.material3.dynamicColor
|
||||
→ 系统壁纸提取 Primary / Secondary / Tertiary
|
||||
→ 支持 Android 12+ (API 31+)
|
||||
→ API 26-30 回退为预设主题色
|
||||
|
||||
备选:用户在设置中手动选择 Seed Color
|
||||
→ 通过 MaterialTheme.colorScheme 的 lightColorScheme/darkColorScheme 生成
|
||||
```
|
||||
|
||||
### 1.2 预设主题色
|
||||
|
||||
| 主题名 | Seed Color | 氛围 |
|
||||
|--------|-----------|------|
|
||||
| 默认(昔涟紫) | `#9C6BFF` (Lavender) | 温柔、亲切 |
|
||||
| 樱花粉 | `#FFB4C8` (Sakura) | 甜美 |
|
||||
| 海洋蓝 | `#6BA4FF` (Ocean) | 清爽 |
|
||||
| 森林绿 | `#6BCF7C` (Forest) | 自然 |
|
||||
| 日落橙 | `#FF9E6B` (Sunset) | 温暖 |
|
||||
|
||||
### 1.3 暗黑模式
|
||||
|
||||
| 属性 | Light | Dark |
|
||||
|------|-------|------|
|
||||
| Surface | `#FFFBFF` | `#1C1B1F` |
|
||||
| Background | `#FFFBFF` | `#1C1B1F` |
|
||||
| Primary | Dynamic | Dynamic (暗黑自适应) |
|
||||
| OnSurface | `#1C1B1F` | `#E6E1E5` |
|
||||
| SurfaceVariant | `#E7E0EC` | `#49454F` |
|
||||
| 遮罩颜色 | `rgba(0,0,0,0.5)` | `rgba(0,0,0,0.7)` |
|
||||
|
||||
### 1.4 悬浮窗专用色
|
||||
|
||||
```
|
||||
覆盖层背景遮罩:
|
||||
Light: rgba(0, 0, 0, 0.5) // 50% 不透明度
|
||||
Dark: rgba(0, 0, 0, 0.7) // 70% 不透明度
|
||||
|
||||
对话卡片背景:
|
||||
Light: MaterialTheme.colorScheme.surface
|
||||
Dark: MaterialTheme.colorScheme.surface
|
||||
|
||||
卡片圆角:28dp (顶部) / 0dp (底部)
|
||||
卡片阴影 (Light):8dp elevation
|
||||
卡片阴影 (Dark):无阴影,用 1dp outline 代替
|
||||
```
|
||||
|
||||
## 2. 字体系统 (Typography)
|
||||
|
||||
| 角色 | 字号 | 字重 | 行高 | 用途 |
|
||||
|------|------|------|------|------|
|
||||
| displayLarge | 57sp | 400 | 64sp | 欢迎页标题 |
|
||||
| headlineMedium | 28sp | 400 | 36sp | 设置页标题 |
|
||||
| titleLarge | 22sp | 400 | 28sp | 对话框标题 |
|
||||
| titleMedium | 16sp | 500 | 24sp | 列表标题 |
|
||||
| bodyLarge | 16sp | 400 | 24sp | 对话气泡文字 |
|
||||
| bodyMedium | 14sp | 400 | 20sp | 辅助文字、时间戳 |
|
||||
| labelLarge | 14sp | 500 | 20sp | 按钮文字 |
|
||||
| labelMedium | 12sp | 500 | 16sp | Tab 标签 |
|
||||
| labelSmall | 11sp | 500 | 16sp | 状态标签 |
|
||||
|
||||
字体家族:`system-ui`(默认),不支持自定义字体以保证加载速度和系统一致性。
|
||||
|
||||
## 3. 形状系统 (Shapes)
|
||||
|
||||
| 角色 | 圆角 | 用途 |
|
||||
|------|------|------|
|
||||
| extraSmall | 4dp | 小标签、芯片 |
|
||||
| small | 8dp | 输入框、按钮 |
|
||||
| medium | 12dp | 卡片、对话框 |
|
||||
| large | 16dp | 大卡片 |
|
||||
| extraLarge | 28dp | 底部弹出卡片、Sheet |
|
||||
|
||||
## 4. 组件规范
|
||||
|
||||
### 4.1 对话气泡
|
||||
|
||||
```
|
||||
昔涟消息 (左侧):
|
||||
┌─────────────────────────────┐
|
||||
│ 🤖 昔涟 10:32 │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ 开拓者,今天心情怎么样? │ │ ← 圆角: 12dp (top-start 4dp)
|
||||
│ └─────────────────────────┘ │ 背景: PrimaryContainer
|
||||
│ │ 文字: OnPrimaryContainer
|
||||
└─────────────────────────────┘
|
||||
|
||||
用户消息 (右侧):
|
||||
┌─────────────────────────────┐
|
||||
│ 你 10:33 │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ 还不错!你呢? │ │ ← 圆角: 12dp (top-end 4dp)
|
||||
│ └─────────────────────┘ │ 背景: Primary
|
||||
│ │ 文字: OnPrimary
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
### 4.2 消息类型样式
|
||||
|
||||
| 类型 | 样式 | 示例 |
|
||||
|------|------|------|
|
||||
| `chat` | 普通气泡 | 对话内容 |
|
||||
| `action` | 居中斜体、灰色 | *昔涟正在查看客厅灯光状态* |
|
||||
| `thinking` | 折叠面板、虚线边框 | 可展开/折叠 |
|
||||
| `system_info` | Toast 样式 | 服务状态告知 |
|
||||
| `tool_progress` | 进度条 + 图标 | IoT 操作进行中 |
|
||||
|
||||
### 4.3 语音输入按钮 (悬浮窗核心组件)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ │
|
||||
│ 🎤 波形动画 │ (LISTENING 状态)
|
||||
│ "我在听..." │
|
||||
│ │
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │ 输入文字或直接说话... │ │ (IDLE 状态,点击切换语音)
|
||||
│ └───────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌────┐ ┌──┐ │
|
||||
│ │ 🎤 │ (按住说话) │⌨️│ │ (WAITING 状态)
|
||||
│ └────┘ └──┘ │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 4.4 昔涟状态指示器
|
||||
|
||||
```
|
||||
在线 (绿色点 + "昔涟"):
|
||||
● 昔涟
|
||||
|
||||
思考中 (黄色脉冲 + "思考中..."):
|
||||
◉ 思考中...
|
||||
|
||||
离线 (灰色 + "离线"):
|
||||
○ 昔涟 · 离线
|
||||
|
||||
说话中 (蓝色波纹 + "正在说话..."):
|
||||
〰 正在说话...
|
||||
```
|
||||
|
||||
### 4.5 IoT 设备卡片
|
||||
|
||||
```
|
||||
┌──────────────────────────┐
|
||||
│ 💡 客厅灯 ● ON │
|
||||
│ ┌──────────────────────┐ │
|
||||
│ │ 亮度 ████████░░ 80% │ │
|
||||
│ │ 色温 ████░░░░░░ 4000K│ │
|
||||
│ └──────────────────────┘ │
|
||||
│ [💡 开关] │
|
||||
└──────────────────────────┘
|
||||
```
|
||||
|
||||
## 5. 动效规范
|
||||
|
||||
| 动效 | 时长 | 曲线 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 覆盖层出现 | 300ms | `FastOutSlowInEasing` | 底部滑入 |
|
||||
| 覆盖层消失 | 250ms | `FastOutLinearInEasing` | 底部滑落 |
|
||||
| 气泡出现 | 200ms | `LinearOutSlowInEasing` | 淡入 + 微上移 |
|
||||
| 涟漪效果 | 400ms | `LinearEasing` | 标准 MD3 ripple |
|
||||
| 页面切换 | 300ms | `FastOutSlowInEasing` | 淡入淡出 |
|
||||
| 波形动画 | 循环 | — | 录制时音频可视化 |
|
||||
| 状态指示脉冲 | 2s 循环 | — | 思考中 / 说话中的呼吸灯效果 |
|
||||
|
||||
## 6. 图标系统
|
||||
|
||||
| 来源 | 用途 |
|
||||
|------|------|
|
||||
| `Icons.Filled` | 导航栏、主要操作按钮 |
|
||||
| `Icons.Outlined` | 列表项、辅助操作 |
|
||||
| `Icons.Rounded` | 芯片、标签 |
|
||||
| 自定义 Lottie | 昔涟头像动画、情感表达 |
|
||||
| 自定义 Vector | 品牌 LOGO、IoT 设备图标 |
|
||||
|
||||
## 7. 悬浮窗 vs 全屏 布局差异
|
||||
|
||||
| 元素 | 全屏 Activity | 悬浮窗 Overlay |
|
||||
|------|-------------|---------------|
|
||||
| TopAppBar | 显示(标题 + 操作) | 不显示 |
|
||||
| BottomNav | 显示(三 Tab) | 不显示 |
|
||||
| 对话区域 | 全屏滚动 | 自适应高度,最大 70% 屏幕 |
|
||||
| 背景 | Surface 纯色 | 半透明遮罩 + 卡片 |
|
||||
| 圆角 | 无 | 顶部 28dp |
|
||||
| 导航返回 | 系统返回键 | 关闭覆盖层 |
|
||||
| IoT 面板 | 完整功能 | 仅限查询,无控制 |
|
||||
| 设置入口 | 完整 | 无(需打开 APP) |
|
||||
|
||||
## 8. 无障碍规范
|
||||
|
||||
- 所有可交互元素提供 `contentDescription`
|
||||
- 语音按钮提供大点击区域(最小 48dp × 48dp)
|
||||
- 支持 TalkBack 导航
|
||||
- 字体缩放:支持系统字体大小设置(最大 200%)
|
||||
- 色彩对比度:满足 WCAG AA 标准(正文 ≥ 4.5:1,大文字 ≥ 3:1)
|
||||
@@ -0,0 +1,272 @@
|
||||
# 04 — 功能规格说明书
|
||||
|
||||
> **版本**:MVP v0.1 → Stable v1.0
|
||||
> **优先级定义**:P0 = 不可缺失 | P1 = 首个正式版必需 | P2 = 后续版本
|
||||
|
||||
---
|
||||
|
||||
## 1. 功能总览
|
||||
|
||||
### MVP (v0.1) — 核心语音助手
|
||||
|
||||
| # | 功能 | 优先级 | 说明 |
|
||||
|---|------|--------|------|
|
||||
| F01 | VoiceInteractionService 注册 | P0 | 系统可识别并设为默认助手 |
|
||||
| F02 | 语音唤醒(热词"昔涟") | P0 | 息屏/亮屏唤醒 |
|
||||
| F03 | 悬浮覆盖层对话 | P0 | VoiceInteractionSession 界面 |
|
||||
| F04 | STT 语音识别 | P0 | 实时语音转文字 |
|
||||
| F05 | TTS 语音合成 | P0 | 文字转语音回复 |
|
||||
| F06 | 实时文字对话 | P0 | WebSocket 双向通信 |
|
||||
| F07 | 用户认证与登录 | P0 | Token 持久化 |
|
||||
|
||||
### v0.5 — 功能完善
|
||||
|
||||
| # | 功能 | 优先级 | 说明 |
|
||||
|---|------|--------|------|
|
||||
| F08 | IoT 设备状态查询 | P1 | 只读查询设备状态 |
|
||||
| F09 | IoT 设备控制 | P1 | 开关/调节设备 |
|
||||
| F10 | 推送通知 (FCM) | P1 | 昔涟主动消息、提醒 |
|
||||
| F11 | 多会话历史 | P1 | 查看历史对话记录 |
|
||||
| F12 | 提醒管理 | P1 | 创建/查看/删除提醒 |
|
||||
| F13 | 全屏 Activity 模式 | P1 | 桌面图标入口、完整功能 |
|
||||
| F14 | 暗黑模式 | P1 | 跟随系统 / 手动切换 |
|
||||
| F15 | 自定义唤醒词 | P2 | 用户可修改唤醒词 |
|
||||
|
||||
### v1.0 — 正式版
|
||||
|
||||
| # | 功能 | 优先级 | 说明 |
|
||||
|---|------|--------|------|
|
||||
| F16 | 记忆查看 | P1 | 浏览昔涟的记忆 |
|
||||
| F17 | 自动化规则 | P2 | 查看/触发自动化场景 |
|
||||
| F18 | 知识库查询 | P2 | 检索知识文档 |
|
||||
| F19 | 文件上传 | P2 | 图片上传与分析 |
|
||||
| F20 | 后台思考展示 | P2 | 查看昔涟的思考内容 |
|
||||
| F21 | 多设备同步 | P2 | Web 端和 Android 端对话同步 |
|
||||
| F22 | 画中画语音通话 | P2 | 持续语音对话的 PIP 模式 |
|
||||
| F23 | 主题自定义 | P2 | 预设主题色切换 |
|
||||
| F24 | 离线兜底 | P2 | 无网络时的本地回复 |
|
||||
|
||||
---
|
||||
|
||||
## 2. P0 功能详细规格
|
||||
|
||||
### F01 · VoiceInteractionService 注册
|
||||
|
||||
**用户故事**:作为用户,我可以在系统设置中将昔涟设为默认语音助手。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] AndroidManifest.xml 正确声明 `VoiceInteractionService`
|
||||
- [ ] 系统 **设置 → 默认应用 → 数字助理** 列表中可见 "昔涟"
|
||||
- [ ] 选中后,长按 Home 键可触发昔涟
|
||||
- [ ] 选中后,底部两角滑动可触发昔涟
|
||||
- [ ] 未设为默认时,APP 内显示引导卡片并一键跳转设置页
|
||||
|
||||
**技术依赖**:无
|
||||
|
||||
---
|
||||
|
||||
### F02 · 语音唤醒
|
||||
|
||||
**用户故事**:作为用户,我可以在息屏或使用其他 APP 时说"昔涟"直接唤起助手。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 息屏状态下说出"昔涟"可唤醒(成功率 ≥ 95%,安静环境)
|
||||
- [ ] 亮屏使用其他 APP 时说出"昔涟"可唤醒
|
||||
- [ ] 唤醒后显示悬浮覆盖层,播放提示音
|
||||
- [ ] 10 分钟无交互自动停止热词监听以省电
|
||||
- [ ] 用户可在设置中开启/关闭息屏唤醒
|
||||
- [ ] 误唤醒率 ≤ 5 次/天(正常使用环境)
|
||||
|
||||
**技术依赖**:F01 (VoiceInteractionService),`CAPTURE_AUDIO_HOTWORD` 权限
|
||||
|
||||
---
|
||||
|
||||
### F03 · 悬浮覆盖层对话
|
||||
|
||||
**用户故事**:作为用户,语音唤醒昔涟后看到半透明覆盖层,不影响当前使用的 APP。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 底部滑入动画 300ms,覆盖层显示
|
||||
- [ ] 半透明黑色遮罩透出底层 APP 内容
|
||||
- [ ] 对话卡片顶部圆角 28dp,自适应高度(最大 70% 屏幕)
|
||||
- [ ] 点击遮罩区域关闭覆盖层
|
||||
- [ ] 下滑卡片关闭覆盖层
|
||||
- [ ] 静默 10 秒自动收起
|
||||
- [ ] 用户说"再见"/"退下"自然结束对话
|
||||
- [ ] 关闭后回到触发前状态,不压入任何 Activity 栈
|
||||
|
||||
**技术依赖**:F01 (VoiceInteractionService)
|
||||
|
||||
---
|
||||
|
||||
### F04 · STT 语音识别
|
||||
|
||||
**用户故事**:作为用户,我可以对昔涟说话,她会实时将我的语音转成文字。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 覆盖层显示时自动开始监听
|
||||
- [ ] 实时显示识别中间结果(流式 STT)
|
||||
- [ ] 语音结束(静默 1.5s)后自动提交识别结果
|
||||
- [ ] 识别结果以用户气泡形式显示在对话中
|
||||
- [ ] 安静环境识别准确率 ≥ 95%(中文普通话)
|
||||
- [ ] 支持噪音环境降噪
|
||||
|
||||
**技术依赖**:后端 Whisper API (voice-service :8093),`RECORD_AUDIO` 权限
|
||||
|
||||
---
|
||||
|
||||
### F05 · TTS 语音合成
|
||||
|
||||
**用户故事**:作为用户,昔涟可以用自然的声音读出她的回复。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 流式 TTS:收到 LLM 第一个 token 即开始合成
|
||||
- [ ] 语音自然流畅,无机械感(使用后端 Edge-TTS 或训练模型)
|
||||
- [ ] 播放完毕自动进入下一轮监听
|
||||
- [ ] 播放期间自动降低其他音频音量(Audio Focus)
|
||||
- [ ] 用户可在设置中调整语速、音量
|
||||
|
||||
**技术依赖**:后端 TTS API (voice-service :8093)
|
||||
|
||||
---
|
||||
|
||||
### F06 · 实时文字对话
|
||||
|
||||
**用户故事**:作为用户,我可以打字与昔涟交流,并实时看到她的回复。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] WebSocket 连接建立后保持心跳 (30s ping)
|
||||
- [ ] 文本消息发送后 200ms 内显示用户气泡
|
||||
- [ ] 昔涟回复流式显示(逐字/逐 token 渲染)
|
||||
- [ ] 正确处理 `chat`、`action`、`thinking` 三种消息类型
|
||||
- [ ] 断线自动重连(指数退避,最多 5 次)
|
||||
- [ ] 连接状态在界面实时指示
|
||||
- [ ] 多条消息按时间顺序排列
|
||||
- [ ] 支持消息滚动到顶部加载历史
|
||||
|
||||
**技术依赖**:后端 Gateway WebSocket (:8080)
|
||||
|
||||
---
|
||||
|
||||
### F07 · 用户认证与登录
|
||||
|
||||
**用户故事**:作为用户,我可以登录我的 Cyrene 账号以同步数据。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 首次启动显示登录页
|
||||
- [ ] 支持输入 Gateway 地址 + 账号 + 密码
|
||||
- [ ] 登录成功保存 JWT Token 到 EncryptedDataStore
|
||||
- [ ] Token 过期自动刷新(refresh token)
|
||||
- [ ] 再次启动自动登录(skip login page)
|
||||
- [ ] 登录失败显示明确错误信息
|
||||
- [ ] 支持退出登录并清除本地数据
|
||||
|
||||
**技术依赖**:后端 Gateway Auth API (:8080)
|
||||
|
||||
---
|
||||
|
||||
## 3. P1 功能详细规格
|
||||
|
||||
### F08 · IoT 设备状态查询
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 全屏 Activity 中 IoT Tab 显示所有设备卡片
|
||||
- [ ] 实时显示设备状态(开/关、亮度、温度等)
|
||||
- [ ] 通过 WebSocket 接收状态变更推送
|
||||
- [ ] 覆盖层模式下支持语音查询("灯开着吗?")
|
||||
- [ ] 覆盖层模式下 IoT 查询结果以文字+卡片形式展示
|
||||
- [ ] 锁屏状态下仅允许查询
|
||||
|
||||
### F09 · IoT 设备控制
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 设备卡片上可直接开关/调节
|
||||
- [ ] 支持语音控制("打开客厅灯")
|
||||
- [ ] 控制结果实时反馈(成功/失败)
|
||||
- [ ] 锁屏状态下禁止控制,提示解锁
|
||||
- [ ] 支持设备白名单(每用户可控制的设备不同)
|
||||
|
||||
### F10 · 推送通知 (FCM)
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 接收昔涟主动消息推送
|
||||
- [ ] 接收提醒到期推送
|
||||
- [ ] 接收 IoT 状态变更推送
|
||||
- [ ] 点击通知打开对应界面
|
||||
- [ ] 通知渠道分组(对话 / 提醒 / IoT / 系统)
|
||||
- [ ] 用户可独立控制各渠道开关
|
||||
|
||||
### F11 · 多会话历史
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 对话列表页展示所有历史会话
|
||||
- [ ] 每条会话显示标题、最后一条消息预览、时间
|
||||
- [ ] 点击进入对应会话详情
|
||||
- [ ] 支持删除会话
|
||||
- [ ] 与 Web 端历史同步
|
||||
|
||||
### F12 · 提醒管理
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 可以语音创建提醒("提醒我下午三点开会")
|
||||
- [ ] 列表展示所有活跃提醒
|
||||
- [ ] 支持删除/标记完成
|
||||
- [ ] 到期时 FCM 推送 + 覆盖层显示
|
||||
|
||||
### F13 · 全屏 Activity 模式
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 桌面图标启动进入全屏界面
|
||||
- [ ] BottomNav 三 Tab(对话 / IoT / 我的)
|
||||
- [ ] 完整的设置页
|
||||
- [ ] 与覆盖层共享同一 WebSocket 连接和 ViewModel
|
||||
|
||||
### F14 · 暗黑模式
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 跟随系统暗黑模式自动切换
|
||||
- [ ] 用户可在设置中手动选择 Light / Dark / Auto
|
||||
- [ ] 覆盖层同步使用当前主题
|
||||
- [ ] 对话气泡、卡片、输入框颜色正确适配
|
||||
|
||||
---
|
||||
|
||||
## 4. P2 功能概要
|
||||
|
||||
| # | 功能 | 关键验收标准 |
|
||||
|---|------|------------|
|
||||
| F15 | 自定义唤醒词 | 设置页可输入自定义词,验证唯一性,测试唤醒效果 |
|
||||
| F16 | 记忆查看 | 时间线展示昔涟记忆,支持搜索过滤 |
|
||||
| F17 | 自动化规则 | 查看规则列表,手动触发,查看执行日志 |
|
||||
| F18 | 知识库查询 | 搜索文档,查看内容,语音问答 |
|
||||
| F19 | 文件上传 | 图片选择/拍照,缩略图预览,AI 分析结果 |
|
||||
| F20 | 后台思考 | 展示昔涟后台思考片段,可折叠面板 |
|
||||
| F21 | 多设备同步 | Web 端和 Android 端对话实时同步 |
|
||||
| F22 | PIP 语音通话 | 切换到 PIP 窗口进行持续语音对话 |
|
||||
| F23 | 主题自定义 | 从预设色中选择,实时预览 |
|
||||
| F24 | 离线兜底 | 无网络时显示离线提示,缓存本地回复模板 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 按开发阶段分组
|
||||
|
||||
### Sprint 1 (MVP):F01 → F07 (P0 全部)
|
||||
目标:可设为系统默认助手,能语音唤醒并对话
|
||||
|
||||
### Sprint 2:F08 → F14 (P1 全部)
|
||||
目标:IoT 控制、全屏界面、推送通知上线
|
||||
|
||||
### Sprint 3+:F15 → F24 (P2 逐个)
|
||||
目标:体验完善、高级功能
|
||||
|
||||
## 6. 非功能需求
|
||||
|
||||
| 类别 | 需求 | 指标 |
|
||||
|------|------|------|
|
||||
| 性能 | 覆盖层冷启动 | < 500ms |
|
||||
| 性能 | 语音识别端到端延迟 | < 2s (STT + LLM + TTS) |
|
||||
| 性能 | WebSocket 消息延迟 | < 100ms |
|
||||
| 稳定性 | 崩溃率 | < 0.5% |
|
||||
| 电量 | 热词监听功耗 | < 3% 电池/小时 (息屏) |
|
||||
| 网络 | 支持弱网 | 切换到低码率 TTS |
|
||||
| 兼容性 | 国内 ROM 适配 | MIUI / ColorOS / OriginOS / HarmonyOS |
|
||||
Reference in New Issue
Block a user