feat(voice): 完善语音交互服务并添加会话启动与辅助数据处理

This commit is contained in:
TongTongStudio
2026-07-28 22:34:10 +08:00
parent e8be46f1a3
commit 3d7452b20f
4 changed files with 111 additions and 9 deletions

View File

@@ -195,6 +195,9 @@
<intent-filter>
<action android:name="android.speech.RecognitionService" />
</intent-filter>
<meta-data
android:name="android.speech"
android:resource="@xml/my_recognition_service" />
</service>
<!-- <receiver-->

View File

@@ -1,15 +1,61 @@
package com.ttstd.dialer.service;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionSession;
import com.ttstd.dialer.utils.Logger;
/**
* 语音交互服务类,作为语音助手的入口。
*/
public class MyVoiceInteractionService extends VoiceInteractionService {
private static final String TAG = "MyVoiceInteractionService";
/**
* 自定义 Action用于从外部启动语音交互会话
*/
public static final String ACTION_SHOW_SESSION = "com.ttstd.dialer.ACTION_SHOW_SESSION";
@Override
public void onCreate() {
super.onCreate();
Logger.d(TAG, "onCreate");
}
@Override
public void onReady() {
super.onReady();
Logger.d(TAG, "onReady");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.d(TAG, "onStartCommand: " + intent);
if (intent != null) {
String action = intent.getAction();
if (ACTION_SHOW_SESSION.equals(action)) {
// 确保服务是当前活跃的语音交互服务
if (isActiveService(this, new ComponentName(this, MyVoiceInteractionService.class))) {
Logger.d(TAG, "Showing session with assist and screenshot flags");
// 核心:调用 showSession 并请求辅助数据AssistStructure和截图
Bundle args = new Bundle();
showSession(args,
VoiceInteractionSession.SHOW_WITH_ASSIST |
VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
} else {
Logger.w(TAG, "Service is not the active voice interaction service");
}
}
}
return START_STICKY;
}
@Override
public void onShutdown() {
super.onShutdown();
Logger.d(TAG, "onShutdown");
}
}

View File

@@ -3,10 +3,15 @@ package com.ttstd.dialer.service;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.service.voice.VoiceInteractionSession;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.ttstd.dialer.utils.Logger;
public class MyVoiceInteractionSession extends VoiceInteractionSession {
@@ -16,24 +21,69 @@ public class MyVoiceInteractionSession extends VoiceInteractionSession {
super(context);
}
@Override
public void onShow(Bundle args, int showFlags) {
super.onShow(args, showFlags);
Logger.d(TAG, "onShow: flags=" + showFlags);
}
@Override
public void onHide() {
super.onHide();
Logger.d(TAG, "onHide");
}
@Override
public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
super.onHandleAssist(data, structure, content);
// 这是核心方法structure 包含了整个屏幕的 View 树
Logger.d(TAG, "onHandleAssist");
if (structure != null) {
AssistStructure.WindowNode windowNode = structure.getWindowNodeAt(0);
Logger.d(TAG, "onHandleAssist: data=" + data);
processAssistStructure(structure);
}
// Android 12 (API 31) 及以上建议使用此方法
@Override
public void onHandleAssist(@NonNull AssistState state) {
super.onHandleAssist(state);
Logger.d(TAG, "onHandleAssist(AssistState)");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
processAssistStructure(state.getAssistStructure());
}
}
@Override
public void onHandleScreenshot(@Nullable Bitmap screenshot) {
super.onHandleScreenshot(screenshot);
Logger.d(TAG, "onHandleScreenshot: " + (screenshot != null ? "has screenshot" : "null"));
}
private void processAssistStructure(AssistStructure structure) {
if (structure == null) {
Logger.w(TAG, "AssistStructure is null");
return;
}
int windowCount = structure.getWindowNodeCount();
Logger.d(TAG, "Window count: " + windowCount);
for (int i = 0; i < windowCount; i++) {
AssistStructure.WindowNode windowNode = structure.getWindowNodeAt(i);
if (windowNode != null) {
traverseNode(windowNode.getRootViewNode(), "");
Logger.d(TAG, "Window[" + i + "]: title=" + windowNode.getTitle());
traverseNode(windowNode.getRootViewNode(), " ");
}
}
}
private void traverseNode(AssistStructure.ViewNode node, String prefix) {
if (node == null) return;
CharSequence text = node.getText();
String id = node.getIdEntry();
String className = node.getClassName();
Logger.d(TAG, prefix + "View: text=" + node.getText() + ", id=" + node.getIdEntry());
if (text != null || id != null) {
Logger.d(TAG, prefix + "View: class=" + className + ", text=" + text + ", id=" + id);
}
for (int i = 0; i < node.getChildCount(); i++) {
traverseNode(node.getChildAt(i), prefix + " ");
}
@@ -41,7 +91,7 @@ public class MyVoiceInteractionSession extends VoiceInteractionSession {
@Override
public View onCreateContentView() {
// 可以返回一个自定义布局,用于在屏幕上显示助手界面
return super.onCreateContentView();
// 返回一个空的 View以确保 Session 能够正确显示
return new View(getContext());
}
}

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<recognition-service xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.ttstd.dialer.activity.settings.home.SettingsActivity" />