可见即可说也叫语音触摸屏,是指在汽车车机/pad/手机等具备智能屏的设备上,通过语音来操控当前页面元素,比如你打开了QQ音乐,首页有一个我的收藏的按钮,你说查看收藏,就等于点击了这个按钮;目前市面上大部分新能源汽车都具有此功能,比如小米、问界、蔚来、小鹏、理想、极越等等。
可见即可说简言之就是:把用户语音转换为控件点击、滑动等事件,具体流程如下:
![](https://img.haomeiwen.com/i3330184/16e6c5d3e295015e.png)
一般来说,可见即可说不是单个App的能力,而是系统全局能力,所以从用户所说到用户意图,信息流转在独立的语音进程中,最后执行点击才进入三方App-QQ音乐进程中,抓手能够将意图跨进程传递给具体的控件或者方法。目前市面上有各种供应商提供的语音语义识别方案,一般使用就是简单的API调用,这里不再详细展开;所以可见即可说另一个关键问题就是如何获取当前页面抓手集合,常见的方案有三种:
-
三方应用客户端运行时注册;
-
在语音进程通过无障碍、OCR、图片识别等手段自动注册。
-
语音模块云端手动配置;
一 、三方应用注册
三方应用注册是指QQ音乐、爱奇艺视频等三方App在每个页面进入前台的时候,通过跨进程通信方式把当前页面所有元素的名称+对应方法名(也叫抓手)添加到语音进程的一个集合中,这个集合叫“当前页面元素抓手集”。
当通过语义识别得到用户意图后,比如是:点击控件“我的收藏”,接下来就从页面元素名称列表中寻找是否有"我的收藏"或者同意词,如果匹配到了,就得到了"我的收藏"这个key绑定的方法(比如是onClickFavorite),接下来跨进程调用这个方法就OK了。
三方应用注册具备较好的精确性和稳定性,但是这种方法需要语音和应用密切配合,应用中侵入了很多的语音注册和控制回调的代码。
二、自动注册
![](https://img.haomeiwen.com/i3330184/60c232a784f5bd22.png)
无障碍服务是Android和IOS等系统提供的一种系统服务,当一个进程启动无障碍服务后,它就能一直监听前台页面元素变化,并能够获取所有元素节点信息(文本、描述)和索引;在通过用户意图匹配到特定节点后,能够根据这个节点的索引发起对该节点代表的页面元素的点击、滑动等操作,在Android中关键代码如下:
/**
* MyAccessibilityService类扩展自AccessibilityService,用于提供无障碍服务。
* 这个类监听系统中发生的可访问性事件,并可以根据事件类型执行相应的自定义操作。
*/
public class MyAccessibilityService extends AccessibilityService {
private static final String TAG = "MyAccessibilityService";
private final Map<String, AccessibilityNodeInfo> mAccessibilityNodes = new HashMap<>();
/**
* 获取访问性节点信息的映射表。
*
* 该方法不接受任何参数。
*
* @return 返回一个包含访问性节点信息的映射表,其中键为节点的唯一标识,值为对应的AccessibilityNodeInfo对象。
*/
public Map<String, AccessibilityNodeInfo> getAccessibilityNodesMap() {
return mAccessibilityNodes;
}
/**
* 当访问性事件发生时的回调方法。此方法会在窗口状态改变或窗口内容改变时被调用。
* 主要用于遍历当前活动窗口的根节点,以执行特定的操作或获取特定的信息。
*
* @param event 代表发生的访问性事件的 AccessibilityEvent 对象。
*/
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// 检查事件类型是否为窗口状态改变或窗口内容改变
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED ||
event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
// 获取当前活动窗口的根节点
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
// 根节点非空时,遍历根节点
if (rootNode != null) {
traverseNode(rootNode);
}
}
}
@Override
public void onInterrupt() {
// Handle interruption of the accessibility service
}
/**
* 遍历并记录AccessibilityNodeInfo树中的每个节点。
* 该函数递归地访问给定节点的所有子节点,并将每个节点的文本或内容描述以及对应的节点对象存储在一个全局映射中。
*
* @param node 要遍历的 AccessibilityNodeInfo 对象。如果为 null,则不执行任何操作。
*/
private void traverseNode(AccessibilityNodeInfo node) {
if (node == null) {
return; // 如果节点为null,则直接返回,不进行任何操作
}
// 获取当前节点的文本或内容描述,并存储该节点
CharSequence contentDescription = node.getContentDescription();
CharSequence text = node.getText();
// 使用文本或内容描述作为键,将节点存储在 mAccessibilityNodes 映射中
String key = text != null ? text.toString() : contentDescription.toString();
mAccessibilityNodes.put(key, node);
// 日志记录当前节点的内容描述和文本
Log.d(TAG, "Node Content Description: " + contentDescription + ", Text: " + text);
// 递归地访问当前节点的每个子节点
for (int i = 0; i < node.getChildCount(); i++) {
traverseNode(node.getChild(i));
}
}
/**
* 对给定的无障碍节点信息执行点击操作。
* @param node 无障碍节点信息对象,代表要执行点击操作的UI元素。
*/
public void performClick(AccessibilityNodeInfo node){
// 执行节点的点击动作
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
但在实际开发中使用无障碍服务来获取元素节点信息时会遇到两种无法处理的情况:
1. 控件无描述无标题,但是控件内的图像中有文本表明这个控件的作用;
2. 控件无描述无标题,但是可以根据控件的图像知道这个控件的意义,比如搜索图标.
对于情况1,我们可以使用OCR来获取控件中文本,OCR(Optical Character Recognition,光学字符识别)是一种技术,用于识别和提取图像中的文本信息;对于情况2 ,我们可以使用图像识别方法给出代表控件图像意义的文本。
小结:自动注册原理和实现过程比较复杂,但可以实现三方应用跟语音完全解耦,三方App中也不用包含语音代码。
三、云端手工配置
云端手工配置是指当前页面的抓手集合是从云端下发的,语音开发同学需要收集每个页面的抓手集合,并提前将它配置到云端;在三方App运行时候,可以通过跨进程、无障碍等方式获取当前页面唯一标记id,然后语音进程根据此id去云端配置平台获取对应的抓手集合,具体实现略。
云端手工配置具备较好的精确性和一定的灵活性,并一定程度解耦了三方App和语音客户端;但是云端配置下发过程中依赖网络,在网络较差情况下会影响体验,另外云端配置是语音云端耦合三方App业务,跟三方应用客户端运行时注册一样,都是适合比较封闭的语音生态。
总结与思考
不管是哪种获取元素抓手的方式都是有优势和劣势,在实际中场景中,我们可以根据具体情况,组合搭配使用,以达到更优的可见即可说效果。
目前语言大模型得到了前所未有的发展,在实现可见即可说时候,可以引入TA来提升整体的兼容性和准确度,比如在抓手匹配中,引入AI语言大模型进行匹配,就能使得用户只要说类似得意思就能匹配成功,大大增加了这个可见即可说的泛化水平(对同一个意思不同说法都兼容,所以具备更加广泛的适用性)。您还想到有什么是可以改进,可以在评论区交流下。
网友评论