InputChannel发送Input给App-Android12

2023-10-27 15:10

本文主要是介绍InputChannel发送Input给App-Android12,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

InputChannel发送Input给App-Android12

android12-release


1. App的ViewRootImpl建立InputChannel

查看 InputChannel通道建立-Android12 1. APP界面建立InputChannel,下面看图:

  • InputChannel / WindowInputEventReceiver建立联系,并建立服务端Connection
  • InputStage责任链:SyntheticInputStage - ViewPostImeInputStage - NativePostImeInputStage - EarlyPostImeInputStage - ImeInputStage - ViewPreImeInputStage - NativePreImeInputStage

在这里插入图片描述

2. InputChannel通过socket发送Input给App

2.1 InputChannel通过socket发送

查看 InputDispatcher线程分发事件-Android12 ,InputPublisher::publishKeyEvent通过mChannel->sendMessage(&msg)发送

  • nWrite = ::send(getFd(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL)目标Fd写入

frameworks/native/libs/input/InputTransport.cpp

status_t InputChannel::sendMessage(const InputMessage* msg) {const size_t msgLength = msg->size();InputMessage cleanMsg;msg->getSanitizedCopy(&cleanMsg);ssize_t nWrite;do {nWrite = ::send(getFd(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);} while (nWrite == -1 && errno == EINTR);if (nWrite < 0) {int error = errno;
#if DEBUG_CHANNEL_MESSAGESALOGD("channel '%s' ~ error sending message of type %d, %s", mName.c_str(),msg->header.type, strerror(error));
#endifif (error == EAGAIN || error == EWOULDBLOCK) {return WOULD_BLOCK;}if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {return DEAD_OBJECT;}return -error;}if (size_t(nWrite) != msgLength) {
#if DEBUG_CHANNEL_MESSAGESALOGD("channel '%s' ~ error sending message type %d, send was incomplete",mName.c_str(), msg->header.type);
#endifreturn DEAD_OBJECT;}#if DEBUG_CHANNEL_MESSAGESALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type);
#endifreturn OK;
}

2.2 WindowInputEventReceiver接收input消息

  • WindowInputEventReceiver中LooperCallback回调handleEvent()在android_view_InputEventReceiver.cpp中,最终调用到WindowInputEventReceiver.onInputEventNativeInputEventReceiver::handleEvent -- consumeEvents -- gInputEventReceiverClassInfo.dispatchInputEvent -> InputEventReceiver.onInputEvent(event) -> WindowInputEventReceiver.onInputEvent

frameworks/base/core/java/android/view/InputEventReceiver.java
frameworks/base/core/jni/android_view_InputEventReceiver.cpp
在这里插入图片描述 在这里插入图片描述

2.3 ViewRootImpl中执行InputStage 责任链

  1. 通过enqueueInputEvent -> doProcessInputEvents -> deliverInputEvent -> stage.deliver(q)调用执行InputStage 责任链
    在这里插入图片描述 在这里插入图片描述
  2. InputStage的各子类Input事件result = onProcess(q)处理,再判断是forward()向下传递,还是finish()结束
abstract class InputStage {// ... ...public final void deliver(QueuedInputEvent q) {if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {forward(q);} else if (shouldDropInputEvent(q)) {finish(q, false);} else {traceEvent(q, Trace.TRACE_TAG_VIEW);final int result;try {result = onProcess(q);} finally {Trace.traceEnd(Trace.TRACE_TAG_VIEW);}apply(q, result);}}/*** Marks the the input event as finished then forwards it to the next stage.*/protected void finish(QueuedInputEvent q, boolean handled) {q.mFlags |= QueuedInputEvent.FLAG_FINISHED;if (handled) {q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;}forward(q);}/*** Forwards the event to the next stage.*/protected void forward(QueuedInputEvent q) {onDeliverToNext(q);}/*** Applies a result code from {@link #onProcess} to the specified event.*/protected void apply(QueuedInputEvent q, int result) {if (result == FORWARD) {forward(q);} else if (result == FINISH_HANDLED) {finish(q, true);} else if (result == FINISH_NOT_HANDLED) {finish(q, false);} else {throw new IllegalArgumentException("Invalid result: " + result);}}/*** Called when an event is ready to be processed.* @return A result code indicating how the event was handled.*/protected int onProcess(QueuedInputEvent q) {return FORWARD;}/*** Called when an event is being delivered to the next stage.*/protected void onDeliverToNext(QueuedInputEvent q) {if (DEBUG_INPUT_STAGES) {Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);}if (mNext != null) {mNext.deliver(q);} else {finishInputEvent(q);}}// ... ...
}

3. 例如ViewPostImeInputStage中processKeyEvent

关注KeyEvent事件分发给APP界面窗口。mView就是App的RootViewImpl.setView设置,涉及PhoneWindow.java、DecorView.java,查看DecorView.dispatchKeyEvent 最终会分发到真正需要处理该时间的窗口。这里handled可以判断应用是否拦截KeyEvent事件,但是需要明白的是不管应用拦不拦截,Input事件都已经发送给应用了。
在这里插入图片描述 在这里插入图片描述

3.1 Activity设置的回调Window.Callback

cb.dispatchKeyEvent(event) 调用到Activity中,这里app可以重载拦截事件。win.superDispatchKeyEvent(event)通过此方法进入view层级中。其具体实现是在PhoneWindow中。
在这里插入图片描述 在这里插入图片描述

3.2 finishInputEvent(q)

最终socket通信发送给服务端执行InputDispatcher::handleReceiveCallback,进行 gotOne 下一个事件发送【IMS:InputDispatcher 接收反馈进行下一次发送】
在这里插入图片描述 在这里插入图片描述

这篇关于InputChannel发送Input给App-Android12的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/286483

相关文章

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试

HTML input 标签示例详解

《HTMLinput标签示例详解》input标签主要用于接收用户的输入,随type属性值的不同,变换其具体功能,本文通过实例图文并茂的形式给大家介绍HTMLinput标签,感兴趣的朋友一... 目录通用属性输入框单行文本输入框 text密码输入框 password数字输入框 number电子邮件输入编程框

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

使用Python和SQLAlchemy实现高效的邮件发送系统

《使用Python和SQLAlchemy实现高效的邮件发送系统》在现代Web应用中,邮件通知是不可或缺的功能之一,无论是订单确认、文件处理结果通知,还是系统告警,邮件都是最常用的通信方式之一,本文将详... 目录引言1. 需求分析2. 数据库设计2.1 User 表(存储用户信息)2.2 CustomerO

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32

Android App安装列表获取方法(实践方案)

《AndroidApp安装列表获取方法(实践方案)》文章介绍了Android11及以上版本获取应用列表的方案调整,包括权限配置、白名单配置和action配置三种方式,并提供了相应的Java和Kotl... 目录前言实现方案         方案概述一、 androidManifest 三种配置方式

如何使用C#串口通讯实现数据的发送和接收

《如何使用C#串口通讯实现数据的发送和接收》本文详细介绍了如何使用C#实现基于串口通讯的数据发送和接收,通过SerialPort类,我们可以轻松实现串口通讯,并结合事件机制实现数据的传递和处理,感兴趣... 目录1. 概述2. 关键技术点2.1 SerialPort类2.2 异步接收数据2.3 数据解析2.

Windows server服务器使用blat命令行发送邮件

《Windowsserver服务器使用blat命令行发送邮件》在linux平台的命令行下可以使用mail命令来发送邮件,windows平台没有内置的命令,但可以使用开源的blat,其官方主页为ht... 目录下载blatBAT命令行示例备注总结在linux平台的命令行下可以使用mail命令来发送邮件,Win

使用Java发送邮件到QQ邮箱的完整指南

《使用Java发送邮件到QQ邮箱的完整指南》在现代软件开发中,邮件发送功能是一个常见的需求,无论是用户注册验证、密码重置,还是系统通知,邮件都是一种重要的通信方式,本文将详细介绍如何使用Java编写程... 目录引言1. 准备工作1.1 获取QQ邮箱的SMTP授权码1.2 添加JavaMail依赖2. 实现