参考前一篇:AccessibilityService可见即可说方案对比-CSDN博客

基于前面创建AccessibilityVoiceCtrlService类,需要把asr VoiceRecognitionService获取的热词传递给AccessibilityVoiceCtrlService。

现在的设计是main activity创建时启动了asr的语音服务VoiceRecognitionService和辅助服务AccessibilityVoiceCtrlService,前者会监控语音输入,转换为热词,后者会监控界面,实时获取所有view节点的文本。前者将获取的热词,传递给后者,触发模拟点击操作。

抽象场景为一个service与另一个service通讯。

安卓系统中会有多个进程,每个进程都是相互独立的,无法共享内存。想要共享进程间的数据,就需要进程通信,AIDL即为IPC机制(跨进程通信)的一种。

注意点:

  • AccessibilityService 本身不是一个服务端,而是一个客户端,用于监听和响应用户界面的事件。

  • AccessibilityService作为一个系统服务,其接口onBind不能重载,所以只能作客户端。

  • VoiceRecognitionService监听语音输入,将语音转化为字符串。属于自定义的service,可以作服务端。

  • 一般用法是客户端给服务端发消息,而这里需要AIDL服务端VoiceRecognitionService主动给客户端AccessibilityVoiceCtrlService发消息,可以用AIDL Callback来实现。

AIDL接口配置步骤:

1、确保 AIDL 文件放在 src/main/aidl/<your_package_name> 目录下,与接口声明的包名一致。

2、检查 AIDL 文件的 import 语句,确保导入路径正确。

3、在 build.gradle 文件中确保有以下配置:

android {
    ...
    sourceSets {
        main {
            aidl.srcDirs = ['src/main/aidl']
        }
    }
    ...
}

4、java文件中,import <your_package_name>.<aidl接口名>;

5、客户端

import com.example.helloworld.AvcAidlInterface;
import com.example.helloworld.AvcAidlCallbackInterface;
import com.example.helloworld.VoiceRecognitionService;

public class AccessibilityVoiceCtrlService extends AccessibilityService {
    private AvcAidlInterface myAidlInterface;
    private final ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myAidlInterface = AvcAidlInterface.Stub.asInterface(service);
            try {
                myAidlInterface.registerCallback(callback, "connect to AIDL server!!!");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            myAidlInterface = null;
        }
    };

    private final AvcAidlCallbackInterface.Stub callback = new AvcAidlCallbackInterface.Stub() {
        @Override
        public boolean hitHotWord(String hotWord) {
            // 处理接收到的消息
            return handlePerformActionByHotWord(hotWord);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "---AccessibilityVoiceCtrlService onCreate");

        Intent intent = new Intent(this, VoiceRecognitionService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unbindService(serviceConnection);
    }

。。。。。。

6、服务端

public class VoiceRecognitionService extends Service {

    private static final String TAG = VoiceRecognitionService.class.getSimpleName();
    private AvcAidlCallbackInterface avcCallback = null;

    private final AvcAidlInterface.Stub binder = new AvcAidlInterface.Stub() {
        @Override
        public void registerCallback(AvcAidlCallbackInterface callback, String desc) throws RemoteException {
            Log.d(TAG, "---AIDL method called!" + desc);
            avcCallback = callback;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

。。。。。。

业务调用点举例:

if (avcCallback != null) {
    if (avcCallback.hitHotWord(keyword)) {
        Log.d(TAG, "---hit word, direct return");
        break;
    }
}

测试能看到handlePerformActionByHotWord里日志,表示调用流程是通畅的,后面就是调整业务了。

更多推荐