背景
bash
$ adb shell wm size
Physical size: 1440x1920
设备屏幕是1440x2050, 但是只有1440x1920是设备的内容显示区域,超出1920的部分称之为下滑条区域,被丝印了。下滑条不参与显示,但要求触摸下滑条区域的事件可以透传到应用层,供应用层接收使用。安卓系统认为超出屏幕外的触摸事件为无效事件,默认会拦截掉。因此需要修改这块的机制才能符合要求。
方案一:透传事件到应用层
触摸事件交由frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp处理,修改让放行屏幕外的触摸事件。
bash
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 14019c77f9..bc1fb95b3e 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1758,10 +1758,16 @@ std::list<NotifyArgs> TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t
}
}
}
- LOG(WARNING) << "Dropping pointer " << id << " at (" << pointer.x << ", " << pointer.y
- << "), it is outside of the physical frame";
- outConsumed = true;
- return out;
+ /* huanghp add: support touchscreen expand area. */
+ bool expandtouch = property_get_bool("persist.odm.touchscreen.expandarea", false);
+ if (expandtouch) {
+ ALOGD_IF(DEBUG_POINTERS,"hhp pointer:%d at (%d, %d ) is not InsidePhysicalFrame, Don't 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);
+ outConsumed = true;
+ return out;
+ }
+ /* huanghp end. */
}
}
事件放行之后,修改frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp让对屏幕外的事件也能找到当前显示的窗口。
DebugConfig.h添加debug调试开关。
bash
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
index fe33d94504..3bc811231c 100644
--- a/services/inputflinger/dispatcher/DebugConfig.h
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -110,5 +110,11 @@ const bool DEBUG_HOVER =
*/
const bool DEBUG_VERIFY_EVENTS = input_flags::enable_inbound_event_verification() ||
android::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAG "VerifyEvents");
-
+//huanghp add
+/**
+ * Log debug messages about huanghp debugging.
+ * Enable this via "adb shell setprop log.tag.InputDispatcherHhp DEBUG" (requires restart)
+ */
+const bool DEBUG_HHP =android::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAG "Hhp");
+//huanghp add end
} // namespace android::inputdispatcher
下面最后一段才是最主要的,让顶层window可以接收到触摸屏外的事件,其它是一些调试日志。
bash
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 8fd3d8469f..837fcd0a6f 100644
--- 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"
+//huanghp add
+#include <cutils/properties.h>
+//huanghp end
#define INDENT " "
#define INDENT2 " "
@@ -154,6 +157,21 @@ const char *kRkHandWriteName = "rk_handwrite_sf";
const size_t kRkHandWriteNameLen = 15;
//------rk code end------
+//huanghp add: read touch screen height
+const int32_t DEFAULT_TOUCH_SCREEN_HEIGHT = 1920;
+static int32_t sTouchScreenHeight=0;
+int32_t getTouchScreenHeight() {
+ if (sTouchScreenHeight<=0){
+ sTouchScreenHeight = property_get_int32("ro.odm.touchscreen.height", DEFAULT_TOUCH_SCREEN_HEIGHT);
+ LOG_IF(WARNING, DEBUG_HHP) << "hhp sTouchScreenHeight:" << sTouchScreenHeight;
+ }
+ if (sTouchScreenHeight<=0){
+ LOG_ALWAYS_FATAL("hhp sTouchScreenHeight:%d, please configure the correct screen height", sTouchScreenHeight);
+ }
+ return sTouchScreenHeight;
+}
+//huanghp end
+
inline nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
}
@@ -1422,6 +1440,7 @@ sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findTouchedWindowAt(
const WindowInfo& info = *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();
return windowHandle;
}
}
@@ -2108,6 +2127,11 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime,
injectionResult = result.error().code();
}
}
+ //huanghp add
+ for (const auto& target : inputTargets) {
+ LOG_IF(WARNING, DEBUG_HHP) << "hhp dispatchMotionLocked inputTarget connection name:" << target.connection->getInputChannelName().c_str();
+ }
+ //huanghp end
if (injectionResult == InputEventInjectionResult::PENDING) {
return false;
}
@@ -2463,7 +2487,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
const bool isStylus = isPointerFromStylus(entry, pointerIndex);
sp<WindowInfoHandle> newTouchedWindowHandle =
mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus);
-
+ LOG_IF(WARNING, DEBUG_HHP) << "hhp newTouchedWindowHandle:" << (newTouchedWindowHandle == nullptr?"is null":newTouchedWindowHandle->getName().c_str()) << ", isStylus:"<<isStylus;
if (isDown) {
targets += findOutsideTargets(displayId, newTouchedWindowHandle, pointer.id, dump);
}
@@ -5353,8 +5377,16 @@ bool InputDispatcher::DispatcherWindowInfo::windowAcceptsTouchAt(const gui::Wind
const auto touchableRegion = displayTransform.transform(windowInfo.touchableRegion);
const auto p = displayTransform.transform(x, y);
if (!touchableRegion.contains(std::floor(p.x), std::floor(p.y))) {
- return false;
+ //huanghp modify: 让顶层window可以接收到触摸屏外的事件,compatible with screen rotation 0(p.y>1920) rotation 90(p.x>1920) rotation 180(p.y<0) rotation 270(p.x<0).
+ if (windowInfo.applicationInfo.token != nullptr && (p.x>getTouchScreenHeight() || p.y>getTouchScreenHeight() || p.x<0 || p.y<0)) {
+ //make sure this is ao app window
+ }else{
+ LOG_IF(WARNING, DEBUG_HHP) << "hhp Window " << windowInfo.name.c_str() << " Don`t accept touch at (" << x << " , " << y << ") in display " << displayId.toString().c_str()<< ", transformed to (" << p.x <<","<< p.y <<"), return false";
+ return false;
+ }
}
+ LOG_IF(WARNING, DEBUG_HHP) << "hhp Window " << windowInfo.name.c_str() << " accept touch at (" << x << " , " << y << ") in display " << displayId.toString().c_str()<< ", transformed to (" << p.x <<","<< p.y <<"), return true";
+ //huanghp end;
return true;
}
最后,应用层通过Activity#onTouchEvent接收事件。
方案二:修改事件类型透传到应用层
首先也是修改frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp让放行屏幕外的触摸事件。
下面
bash
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 14019c77f9..5a08255dfb 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1658,6 +1658,21 @@ std::list<NotifyArgs> TouchInputMapper::updateExternalStylusState(const StylusSt
std::list<NotifyArgs> TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t readTime,
uint32_t policyFlags, bool& outConsumed) {
//修改mSource为AINPUT_SOURCE_TOUCHPAD
+ /* changed huanghp: if inside surface set to touchscreen for expandtouch. */
+ bool expandtouch = property_get_bool("persist.odm.touchscreen.expandarea", false);
+ uint32_t id_ = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
+ const RawPointerData::Pointer &pointer_ = mCurrentRawState.rawPointerData.pointerForId(id_);
+ uint32_t id2_ = mLastRawState.rawPointerData.touchingIdBits.firstMarkedBit();
+ const RawPointerData::Pointer &pointer2_ = mLastRawState.rawPointerData.pointerForId(id2_);
+ if (mSource == AINPUT_SOURCE_TOUCHSCREEN || mSource == AINPUT_SOURCE_TOUCHPAD) {
+ bool pointInsideScreen=mCurrentRawState.rawPointerData.pointerCount==0?isPointInsidePhysicalFrame(pointer2_.x, pointer2_.y):isPointInsidePhysicalFrame(pointer_.x, pointer_.y);
+ if (expandtouch && !pointInsideScreen) {
+ mSource = AINPUT_SOURCE_TOUCHPAD;
+ } else {
+ mSource = AINPUT_SOURCE_TOUCHSCREEN;
+ }
+ }
+ /* changed end. */
outConsumed = false;
std::list<NotifyArgs> out;
// Check for release of a virtual key.
@@ -1758,10 +1773,19 @@ std::list<NotifyArgs> TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t
}
}
}
- LOG(WARNING) << "Dropping pointer " << id << " at (" << pointer.x << ", " << pointer.y
- << "), it is outside of the physical frame";
- outConsumed = true;
- return out;
+ /* huanghp modify: support touchscreen expand area. */
+ // LOG(WARNING) << "Dropping pointer " << id << " at (" << pointer.x << ", " << pointer.y
+ // << "), it is outside of the physical frame";
+ // outConsumed = true;
+ // return out;
+ if ((mSource != AINPUT_SOURCE_TOUCHSCREEN && mSource != AINPUT_SOURCE_TOUCHPAD) || !expandtouch) {
+ outConsumed = true;
+ LOG(WARNING) << "Dropping pointer " << id << " at (" << pointer.x << ", " << pointer.y<< "), it is outside of the physical frame";
+ return out;
+ }else { //放行屏外事件
+ LOG(WARNING) << "not Dropping pointer " << id << " at (" << pointer.x << ", " << pointer.y<< "), it is outside of the physical frame";
+ }
+ /* huanghp end. */
}
}
因为中途修改了事件类型,且只根据第一个触摸点作的判断逻辑,当多指触摸的时候,会出现判断错误导致事件类型前后匹配不上以至出现错误的事件序列,android16中InputDispatcher会严格校验事件类型以及乱序的事件序列,出现不合规的行为会导致系统重启,需要移除这部分的合规校验。
bash
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 8fd3d8469f..09eccf321b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3852,7 +3852,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
status = publishMotionEvent(*connection, *dispatchEntry);
if (status == BAD_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_ptr<MotionEntry> InputDispatcher::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 end
return nullptr;
}
const auto& [action, pointerProperties, pointerCoords] = *result;
@@ -4444,9 +4448,11 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
// correctly.
if (action == AMOTION_EVENT_ACTION_DOWN && splitDownTime != originalMotionEntry.eventTime) {
logDispatchStateLocked();
- LOG_ALWAYS_FATAL("Split motion event has mismatching downTime and eventTime for "
+ //huanghp add: fix 触摸灵动条时同时多指狂点屏幕导致系统重启(fix InputDispatcher crash cause of reboot when if condition is true)
+ ALOGE_IF("Split motion event has mismatching downTime and eventTime for "
"ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64 "ns",
originalMotionEntry.getDescription().c_str(), splitDownTime);
+ //huanghp end
}
int32_t newId = mIdGenerator.nextId();
@@ -4625,7 +4631,9 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) {
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接收事件。