背景$ adb shell wm size Physical size: 1440x1920设备屏幕是1440x2050, 但是只有1440x1920是设备的内容显示区域超出1920的部分称之为下滑条区域被丝印了。下滑条不参与显示但要求触摸下滑条区域的事件可以透传到应用层供应用层接收使用。安卓系统认为超出屏幕外的触摸事件为无效事件默认会拦截掉。因此需要修改这块的机制才能符合要求。方案一透传事件到应用层触摸事件交由frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp处理修改让放行屏幕外的触摸事件。diff--gita/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 14019c77f9..bc1fb95b3e100644--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp -1758,10 1758,16 std::listNotifyArgsTouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t}}}- LOG(WARNING)Dropping pointer id at (pointer.x, pointer.y -), it is outside of the physical frame;- outConsumedtrue;-returnout; /* huanghp add: support touchscreenexpandarea. */ bool expandtouchproperty_get_bool(persist.odm.touchscreen.expandarea,false);if(expandtouch){ ALOGD_IF(DEBUG_POINTERS,hhp pointer:%d at (%d, %d ) is not InsidePhysicalFrame, Dont Dropping it , id, pointer.x, pointer.y);}else{ ALOGD_IF(DEBUG_POINTERS,hhp pointer:%d at (%d, %d ) is not InsidePhysicalFrame, Dropping it , id, pointer.x, pointer.y); outConsumedtrue;returnout;} /* huanghp end. */}}事件放行之后修改frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp让对屏幕外的事件也能找到当前显示的窗口。DebugConfig.h添加debug调试开关。diff--gita/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h index fe33d94504..3bc811231c100644--- a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h -110,5 110,11 const bool DEBUG_HOVER*/ const bool DEBUG_VERIFY_EVENTSinput_flags::enable_inbound_event_verification()||android::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAGVerifyEvents);- //huanghpadd/** * Log debug messages about huanghp debugging. * Enable this viaadb shell setprop log.tag.InputDispatcherHhp DEBUG(requires restart) */ const bool DEBUG_HHPandroid::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAGHhp);//huanghpaddend}// namespace android::inputdispatcher下面最后一段才是最主要的让顶层window可以接收到触摸屏外的事件其它是一些调试日志。diff--gita/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 8fd3d8469f..837fcd0a6f100644--- a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp -56,6 56,9 #include InputEventTimeline.h#include InputTracingThreadedBackend.h#include trace/InputTracer.h//huanghpadd#include cutils/properties.h//huanghp end#define INDENT #define INDENT2 -154,6 157,21 const char *kRkHandWriteNamerk_handwrite_sf;const size_t kRkHandWriteNameLen15;//------rk code end------ //huanghp add:readtouchscreenheight const int32_t DEFAULT_TOUCH_SCREEN_HEIGHT1920;static int32_tsTouchScreenHeight0;int32_tgetTouchScreenHeight(){if(sTouchScreenHeight0){ sTouchScreenHeightproperty_get_int32(ro.odm.touchscreen.height, DEFAULT_TOUCH_SCREEN_HEIGHT); LOG_IF(WARNING, DEBUG_HHP)hhp sTouchScreenHeight:sTouchScreenHeight;}if(sTouchScreenHeight0){ LOG_ALWAYS_FATAL(hhp sTouchScreenHeight:%d, please configure the correct screen height, sTouchScreenHeight);}returnsTouchScreenHeight;}//huanghp end inline nsecs_tnow(){returnsystemTime(SYSTEM_TIME_MONOTONIC);} -1422,6 1440,7 spWindowInfoHandleInputDispatcher::DispatcherWindowInfo::findTouchedWindowAt(const WindowInfoinfo*windowHandle-getInfo();if(!info.isSpy()windowAcceptsTouchAt(info, displayId, x, y, isStylus)){ LOG_IF(WARNING, DEBUG_HHP)hhp Found touched window:info.name.c_str() for touch at (x , y) isSpy:info.isSpy();returnwindowHandle;}} -2108,6 2127,11 bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, injectionResultresult.error().code();}} //huanghpaddfor(const autotarget:inputTargets){ LOG_IF(WARNING, DEBUG_HHP)hhp dispatchMotionLocked inputTarget connection name:target.connection-getInputChannelName().c_str();} //huanghp endif(injectionResultInputEventInjectionResult::PENDING){returnfalse;} -2463,7 2487,7 InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(const bool isStylusisPointerFromStylus(entry, pointerIndex);spWindowInfoHandlenewTouchedWindowHandlemWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus);- LOG_IF(WARNING, DEBUG_HHP)hhp newTouchedWindowHandle:(newTouchedWindowHandlenullptr?is null:newTouchedWindowHandle-getName().c_str()), isStylus:isStylus;if(isDown){targetsfindOutsideTargets(displayId, newTouchedWindowHandle, pointer.id, dump);} -5353,8 5377,16 bool InputDispatcher::DispatcherWindowInfo::windowAcceptsTouchAt(const gui::Wind const auto touchableRegiondisplayTransform.transform(windowInfo.touchableRegion);const auto pdisplayTransform.transform(x, y);if(!touchableRegion.contains(std::floor(p.x), std::floor(p.y))){-returnfalse; //huanghp modify: 让顶层window可以接收到触摸屏外的事件compatible withscreenrotation0(p.y1920)rotation90(p.x1920)rotation180(p.y0)rotation270(p.x0). if(windowInfo.applicationInfo.token!nullptr(p.xgetTouchScreenHeight()||p.ygetTouchScreenHeight()||p.x0||p.y0)){ //make sure this is ao app window }else{ LOG_IF(WARNING, DEBUG_HHP)hhp Window windowInfo.name.c_str() Dont accepttouchat( x , y )indisplay displayId.toString().c_str() , transformed to( p.x , p.y ),returnfalse; return false; } } LOG_IF(WARNING, DEBUG_HHP) hhp Window windowInfo.name.c_str() accepttouchat( x , y )indisplay displayId.toString().c_str() , transformed to( p.x , p.y ),returntrue; //huanghp end;returntrue;}最后应用层通过Activity#onTouchEvent接收事件。方案二修改事件类型透传到应用层首先也是修改frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp让放行屏幕外的触摸事件。下面diff--gita/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 14019c77f9..5a08255dfb100644--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp -1658,6 1658,21 std::listNotifyArgsTouchInputMapper::updateExternalStylusState(const StylusSt std::listNotifyArgsTouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags, booloutConsumed){//修改mSource为AINPUT_SOURCE_TOUCHPAD /* changed huanghp:ifinside surfacesetto touchscreenforexpandtouch. */ bool expandtouchproperty_get_bool(persist.odm.touchscreen.expandarea,false); uint32_t id_mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); const RawPointerData::Pointerpointer_mCurrentRawState.rawPointerData.pointerForId(id_); uint32_t id2_mLastRawState.rawPointerData.touchingIdBits.firstMarkedBit(); const RawPointerData::Pointerpointer2_mLastRawState.rawPointerData.pointerForId(id2_);if(mSourceAINPUT_SOURCE_TOUCHSCREEN||mSourceAINPUT_SOURCE_TOUCHPAD){ boolpointInsideScreenmCurrentRawState.rawPointerData.pointerCount0?isPointInsidePhysicalFrame(pointer2_.x, pointer2_.y):isPointInsidePhysicalFrame(pointer_.x, pointer_.y);if(expandtouch!pointInsideScreen){ mSourceAINPUT_SOURCE_TOUCHPAD;}else{ mSourceAINPUT_SOURCE_TOUCHSCREEN;}} /* changed end. */ outConsumedfalse;std::listNotifyArgsout;// Checkforrelease of a virtual key. -1758,10 1773,19 std::listNotifyArgsTouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t}}}- LOG(WARNING)Dropping pointer id at (pointer.x, pointer.y -), it is outside of the physical frame;- outConsumedtrue;-returnout; /* huanghp modify: support touchscreenexpandarea. */ // LOG(WARNING)Dropping pointer id at (pointer.x, pointer.y //), it is outside of the physical frame; // outConsumedtrue; //returnout;if((mSource!AINPUT_SOURCE_TOUCHSCREENmSource!AINPUT_SOURCE_TOUCHPAD)||!expandtouch){ outConsumedtrue; LOG(WARNING)Dropping pointer id at (pointer.x, pointer.y), it is outside of the physical frame;returnout;}else{//放行屏外事件 LOG(WARNING)not Dropping pointer id at (pointer.x, pointer.y), it is outside of the physical frame;} /* huanghp end. */}}因为中途修改了事件类型且只根据第一个触摸点作的判断逻辑当多指触摸的时候会出现判断错误导致事件类型前后匹配不上以至出现错误的事件序列android16中InputDispatcher会严格校验事件类型以及乱序的事件序列出现不合规的行为会导致系统重启需要移除这部分的合规校验。diff--gita/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 8fd3d8469f..09eccf321b100644--- a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp -3852,7 3852,9 void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, statuspublishMotionEvent(*connection, *dispatchEntry);if(statusBAD_VALUE){logDispatchStateLocked();- LOG(FATAL)Publisher failed for motionEntry; //huanghp modify:log the details instead of cause a fatal LOG(ERROR)Publisher failed for motionEntry; //huanghp end}if(mTracer){ensureEventTraced(motionEntry); -4419,8 4421,10 std::unique_ptrMotionEntryInputDispatcher::splitMotionEvent(originalMotionEntry.pointerCoords, pointerIds);if(!result.ok()){logDispatchStateLocked();- LOG(FATAL)Could not split motion: originalMotionEntry //huanghp modify:log the details instead of cause a fatal LOG(ERROR)Could not split motion: originalMotionEntry, pointers: pointerIds : result.error(); //huanghp endreturnnullptr;}const auto[action, pointerProperties, pointerCoords]*result; -4444,9 4448,11 std::unique_ptrMotionEntryInputDispatcher::splitMotionEvent(// correctly.if(actionAMOTION_EVENT_ACTION_DOWNsplitDownTime!originalMotionEntry.eventTime){logDispatchStateLocked();- LOG_ALWAYS_FATAL(Split motion event has mismatching downTime and eventTime for //huanghp add: fix 触摸灵动条时同时多指狂点屏幕导致系统重启(fix InputDispatcher crash cause ofrebootwhenifcondition istrue) ALOGE_IF(Split motion event has mismatching downTime and eventTime for ACTION_DOWN, motionEntry%s, splitDownTime%PRId64ns, originalMotionEntry.getDescription().c_str(), splitDownTime); //huanghp end}int32_t newIdmIdGenerator.nextId(); -4625,7 4631,9 void InputDispatcher::notifyMotion(const NotifyMotionArgsargs){args.pointerProperties.data(), args.pointerCoords.data(), args.flags, args.buttonState);if(!result.ok()){- LOG(FATAL)Bad stream: result.error() caused by args.dump(); //huanghp modify:log the details instead of cause a fatal LOG(ERROR)Bad stream: result.error() caused by args.dump(); //huanghp end}}最后应用层通过Activity#onGenericMotionEvent接收事件。