当前位置: 首页 > news >正文

【Android】输入路由

【Android】输入路由

Android,可以通过配置 input-port-associations.xml,将Display和Input(屏幕输入)节点关联起来。

<ports><port display="0" input="linduoDev-1.0/input0" /><port display="1" input="linduoDev-2.0/input0" />
</ports>

display="0"指定屏幕接口,input="linduoDev-1.0/input0"指定输入设备接口。可以通过下述命令查看配置关系

adb shell dumpsys input

相关源码流程

解析input-port-associations.xml
  • IMS(InputManagerService.java)
private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";private static Map<String, Integer> loadStaticInputPortAssociations() {        final File baseDir = Environment.getVendorDirectory();final File confFile = new File(baseDir, PORT_ASSOCIATIONS_PATH);try {final InputStream stream = new FileInputStream(confFile);return ConfigurationProcessor.processInputPortAssociations(stream);} catch (FileNotFoundException e) {// Most of the time, file will not exist, which is expected.} catch (Exception e) {Slog.e(TAG, "Could not parse '" + confFile.getAbsolutePath() + "'", e);}return new HashMap<>();
}
  • 解析的内容后的格式为<key>:InputPort<value>:DipslayPort
@VisibleForTesting    
static Map<String, Integer> processInputPortAssociations(InputStream xml) throws Exception {Map<String, Integer> associations = new HashMap<String, Integer>();{TypedXmlPullParser parser = Xml.resolvePullParser(xml);XmlUtils.beginDocument(parser, "ports");while (true) {XmlUtils.nextElement(parser);String entryName = parser.getName();if (!"port".equals(entryName)) {break;}String inputPort = parser.getAttributeValue(null, "input");String displayPortStr = parser.getAttributeValue(null, "display");if (TextUtils.isEmpty(inputPort) || TextUtils.isEmpty(displayPortStr)) {continue;}try {int displayPort = Integer.parseUnsignedInt(displayPortStr);associations.put(inputPort, displayPort);} catch (NumberFormatException e) {Slog.wtf(TAG, "Display port should be an integer");}}}return associations;
}
  • IMS通过JNI Callback,将InputPort:DisplayPort信息,传输到IMS的Native层。
// Native callback    
private String[] getInputPortAssociations() {final Map<String, Integer> associations = new HashMap<>(mStaticAssociations);// merge the runtime associations.synchronized (mAssociationsLock) {associations.putAll(mRuntimeAssociations);}return flatten(associations);
}
  • JNI代码对应(com_android_server_input_InputManagerService.cpp)。读取InputPort、DisplayPort的配置。并设置DisplayViewPort
void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) {    ATRACE_CALL();// Associations between input ports and display ports// The java method packs the information in the following manner:// Original data: [{'inputPort1': '1'}, {'inputPort2': '2'}]// Received data: ['inputPort1', '1', 'inputPort2', '2']// So we unpack accordingly here.outConfig->portAssociations.clear();jobjectArray portAssociations = jobjectArray(env->CallObjectMethod(mServiceObj,gServiceClassInfo.getInputPortAssociations));if (!checkAndClearExceptionFromCallback(env, "getInputPortAssociations") && portAssociations) {jsize length = env->GetArrayLength(portAssociations);for (jsize i = 0; i < length / 2; i++) {std::string inputPort = getStringElementFromJavaArray(env, portAssociations, 2 * i);std::string displayPortStr =getStringElementFromJavaArray(env, portAssociations, 2 * i + 1);uint8_t displayPort;// Should already have been validated earlier, but do it here for safety.bool success = ParseUint(displayPortStr, &displayPort);if (!success) {ALOGE("Could not parse entry in port configuration file, received: %s",displayPortStr.c_str());continue;}outConfig->portAssociations.insert({inputPort, displayPort});}env->DeleteLocalRef(portAssociations);}{ // acquire lockAutoMutex _l(mLock);outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed* POINTER_SPEED_EXPONENT);outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled;outConfig->showTouches = mLocked.showTouches;outConfig->pointerCapture = mLocked.pointerCapture;outConfig->setDisplayViewports(mLocked.viewports);outConfig->defaultPointerDisplayId = mLocked.pointerDisplayId;outConfig->disabledDevices = mLocked.disabledInputDevices;} // release lock
}
  • InputReader通过调用getReaderConfiguration获取到配置信息。然后通知InputDevice配置信息。
void InputReader::refreshConfigurationLocked(uint32_t changes) {    mPolicy->getReaderConfiguration(&mConfig);mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);if (!changes) return;ALOGI("Reconfiguring input devices, changes=%s",InputReaderConfiguration::changesToString(changes).c_str());nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) {updatePointerDisplayLocked();}if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {mEventHub->requestReopenDevices();} else {for (auto& devicePair : mDevices) {std::shared_ptr<InputDevice>& device = devicePair.second;device->configure(now, &mConfig, changes);}}if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,mConfig.pointerCapture);mQueuedListener->notifyPointerCaptureChanged(&args);}
}
  • 在InputDevice的configure中。拿到InputDevice关联的ViewPort
void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,uint32_t changes) {if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {bool enabled = (config->disabledDevices.find(mId) == config->disabledDevices.end());if (mAssociatedDisplayPort) {mAssociatedViewport = config->getDisplayViewportByPort(*mAssociatedDisplayPort);} else if (mAssociatedDisplayUniqueId != std::nullopt) {mAssociatedViewport =config->getDisplayViewportByUniqueId(*mAssociatedDisplayUniqueId);}if (changes) {// For first-time configuration, only allow device to be disabled after mappers have// finished configuring. This is because we need to read some of the properties from// the device's open fd.setEnabled(enabled, when);}}
}
  • DisplayViewPort为Input派发提供信息,该数据结构信息如下
enum class ViewportType : int32_t {INTERNAL = 1,EXTERNAL = 2,VIRTUAL = 3,
};/** Describes how coordinates are mapped on a physical display.* See com.android.server.display.DisplayViewport.*/struct DisplayViewport {int32_t displayId; // -1 if invalidint32_t orientation;int32_t logicalLeft;int32_t logicalTop;int32_t logicalRight;int32_t logicalBottom;int32_t physicalLeft;int32_t physicalTop;int32_t physicalRight;int32_t physicalBottom;int32_t deviceWidth;int32_t deviceHeight;bool isActive;std::string uniqueId;// The actual (hardware) port that the associated display is connected to.// Not all viewports will have this specified.std::optional<uint8_t> physicalPort;ViewportType type;}
  • InputReader会根据InputPort找到对应的InputDevice,将对应的Input信息传输给InputDevice,然后InputDevice根据自己的DisplayViewPort,将Touch派发给对应的DisplayID(TouchInputMapper.cpp)
void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t policyFlags,uint32_t source, int32_t action, int32_t actionButton,int32_t flags, int32_t metaState, int32_t buttonState,int32_t edgeFlags, const PointerProperties* properties,const PointerCoords* coords, const uint32_t* idToIndex,BitSet32 idBits, int32_t changedId, float xPrecision,float yPrecision, nsecs_t downTime) {const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);const int32_t deviceId = getDeviceId();std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();std::for_each(frames.begin(), frames.end(),[this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,policyFlags, action, actionButton, flags, metaState, buttonState,MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,downTime, std::move(frames));getListener()->notifyMotion(&args);
}
http://www.xdnf.cn/news/1056835.html

相关文章:

  • 将CVAT点云格式标注格式由datumaro转换为kitti格式
  • 软件测试用例(一)
  • Java锁机制:ReentrantLock深度解析与锁粒度优化实践(时序图详解)
  • 交互式编程:编程范式的静默革命
  • 在windows10上安装nvm以及配置环境
  • 【推荐】城市灾害应急管理系统【面试模拟题目——字节跳动面试原题】
  • java复习 13
  • (二十八)深度解析领域特定语言(DSL)第六章——语法分析:巴科斯-诺尔范式
  • 适合 Acrobat DC 文件类型解析
  • 6.15 操作系统面试题 锁 内存管理
  • Appium + .NET 测试全流程
  • 【模拟 贪心】B4207 [常州市赛 2021] 战士|普及+
  • XP POWER EJ ET EY FJ FR 系列软件和驱动程序和手侧
  • verl multi-node train 教程
  • 红花多组学挖掘OGT1-文献精读146
  • Git开发流程
  • 两个渐开线花键需要共用一把滚刀
  • 【unitrix】 1.8 常量约束(const_traits.rs)
  • SOLIDWORKS的“12”个简单高效的草图绘制规则,全部应用成为草图大师!
  • SpringBoot常用注解
  • C++ Builder xe 关于ListView的自然排序功能排序效果与Windows资源管理器相同
  • 蛋白分析工具和数据库
  • 鼓励建设性对抗,反对攻击性评论
  • 计量经济学EViews软件题与证明题预测
  • Java 多线程轮流打印 ABC 的 4 种实现方式详解
  • 关于脉冲功率技术的认识
  • 【Python训练营打卡】day53 @浙大疏锦行
  • Java30:SpringBoot3
  • 数据库优化实战分享
  • Python 基础语法(3)【适合0基础】