From 3d7452b20fcd8edfd283e7d7010cc8ef931def2e Mon Sep 17 00:00:00 2001 From: TongTongStudio Date: Tue, 28 Jul 2026 22:34:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(voice):=20=E5=AE=8C=E5=96=84=E8=AF=AD?= =?UTF-8?q?=E9=9F=B3=E4=BA=A4=E4=BA=92=E6=9C=8D=E5=8A=A1=E5=B9=B6=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=BC=9A=E8=AF=9D=E5=90=AF=E5=8A=A8=E4=B8=8E=E8=BE=85?= =?UTF-8?q?=E5=8A=A9=E6=95=B0=E6=8D=AE=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 3 + .../service/MyVoiceInteractionService.java | 46 +++++++++++++ .../service/MyVoiceInteractionSession.java | 68 ++++++++++++++++--- .../main/res/xml/my_recognition_service.xml | 3 + 4 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 app/src/main/res/xml/my_recognition_service.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8a92b45..bf376cf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -195,6 +195,9 @@ + diff --git a/app/src/main/java/com/ttstd/dialer/service/MyVoiceInteractionService.java b/app/src/main/java/com/ttstd/dialer/service/MyVoiceInteractionService.java index b467813..e9930e9 100644 --- a/app/src/main/java/com/ttstd/dialer/service/MyVoiceInteractionService.java +++ b/app/src/main/java/com/ttstd/dialer/service/MyVoiceInteractionService.java @@ -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"); + } } diff --git a/app/src/main/java/com/ttstd/dialer/service/MyVoiceInteractionSession.java b/app/src/main/java/com/ttstd/dialer/service/MyVoiceInteractionSession.java index 841f85b..27a06d2 100644 --- a/app/src/main/java/com/ttstd/dialer/service/MyVoiceInteractionSession.java +++ b/app/src/main/java/com/ttstd/dialer/service/MyVoiceInteractionSession.java @@ -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()); } } diff --git a/app/src/main/res/xml/my_recognition_service.xml b/app/src/main/res/xml/my_recognition_service.xml new file mode 100644 index 0000000..e5891d6 --- /dev/null +++ b/app/src/main/res/xml/my_recognition_service.xml @@ -0,0 +1,3 @@ + +