Loading services/inputflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ filegroup { srcs: [ "InputClassifier.cpp", "InputCommonConverter.cpp", "PreferStylusOverTouchBlocker.cpp", "UnwantedInteractionBlocker.cpp", "InputManager.cpp", ], Loading services/inputflinger/PreferStylusOverTouchBlocker.cpp 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "PreferStylusOverTouchBlocker.h" #include <android-base/stringprintf.h> using android::base::StringPrintf; static const char* toString(bool value) { return value ? "true" : "false"; } namespace android { ftl::StaticVector<NotifyMotionArgs, 2> PreferStylusOverTouchBlocker::processMotion( const NotifyMotionArgs& args) { const bool isStylusEvent = isFromSource(args.source, AINPUT_SOURCE_STYLUS); if (isStylusEvent) { for (size_t i = 0; i < args.pointerCount; i++) { // Make sure we are canceling stylus pointers const int32_t toolType = args.pointerProperties[i].toolType; LOG_ALWAYS_FATAL_IF(toolType != AMOTION_EVENT_TOOL_TYPE_STYLUS && toolType != AMOTION_EVENT_TOOL_TYPE_ERASER, "The pointer %zu has toolType=%i, but the source is STYLUS. If " "simultaneous touch and stylus is supported, " "'PreferStylusOverTouchBlocker' should be disabled.", i, toolType); } } const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN; const bool isUpOrCancel = args.action == AMOTION_EVENT_ACTION_UP || args.action == AMOTION_EVENT_ACTION_CANCEL; if (isStylusEvent) { if (isDown) { // Reject all touch while stylus is down mIsStylusDown = true; if (mIsTouchDown && !mCurrentTouchIsCanceled) { // Cancel touch! mCurrentTouchIsCanceled = true; mLastTouchEvent.action = AMOTION_EVENT_ACTION_CANCEL; mLastTouchEvent.flags |= AMOTION_EVENT_FLAG_CANCELED; mLastTouchEvent.eventTime = systemTime(SYSTEM_TIME_MONOTONIC); return {mLastTouchEvent, args}; } } if (isUpOrCancel) { mIsStylusDown = false; } // Never drop stylus events return {args}; } const bool isTouchEvent = isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN) && !isStylusEvent; if (isTouchEvent) { if (mIsStylusDown) { mCurrentTouchIsCanceled = true; } // If we already canceled the current gesture, then continue to drop events from it, even if // the stylus has been lifted. if (mCurrentTouchIsCanceled) { if (isUpOrCancel) { mCurrentTouchIsCanceled = false; } return {}; } // Update state mLastTouchEvent = args; if (isDown) { mIsTouchDown = true; } if (isUpOrCancel) { mIsTouchDown = false; mCurrentTouchIsCanceled = false; } return {args}; } // Not a touch or stylus event return {args}; } std::string PreferStylusOverTouchBlocker::dump() { std::string out; out += StringPrintf("mIsTouchDown: %s\n", toString(mIsTouchDown)); out += StringPrintf("mIsStylusDown: %s\n", toString(mIsStylusDown)); out += StringPrintf("mLastTouchEvent: %s\n", mLastTouchEvent.dump().c_str()); out += StringPrintf("mCurrentTouchIsCanceled: %s\n", toString(mCurrentTouchIsCanceled)); return out; } } // namespace android services/inputflinger/PreferStylusOverTouchBlocker.h 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <ftl/static_vector.h> #include <optional> #include "InputListener.h" namespace android { /** * When stylus is down, we ignore all touch. * TODO(b/210159205): delete this when simultaneous stylus and touch is supported */ class PreferStylusOverTouchBlocker { public: /** * Process the provided event and emit up to 2 events in response. * In the majority of cases, the returned result will just be the provided args (array with * only 1 element), unmodified. * * If the gesture should be blocked, the returned result may be: * * a) An empty array, if the current event should just be ignored completely * b) An array of 2 elements, containing an event with ACTION_CANCEL and the current event. * * bool is set to 'true'. * NotifyMotionArgs potentially contains an event that should be used to cancel the existing * gesture. * * If the event should not be blocked, bool contains 'false'. */ ftl::StaticVector<NotifyMotionArgs, 2> processMotion(const NotifyMotionArgs& args); std::string dump(); private: bool mIsTouchDown = false; bool mIsStylusDown = false; // Provide some default values for the stored MotionEvent to allow printint the event before // any real event is received. NotifyMotionArgs mLastTouchEvent{0 /*id*/, 0 /*eventTime*/, 0 /*readTime*/, 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, 0 /*displayId*/, 0 /*policyFlags*/, 0 /*action*/, 0 /*actionButton*/, 0 /*flags*/, 0 /*metaState*/, 0 /*buttonState*/, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 0 /*pointerCount*/, nullptr /*properties*/, nullptr /*coords*/, 0. /*xPrecision*/, 0. /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, {}}; bool mCurrentTouchIsCanceled = false; }; } // namespace android No newline at end of file services/inputflinger/UnwantedInteractionBlocker.cpp +12 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,8 @@ static std::string toLower(std::string s) { } static bool isFromTouchscreen(int32_t source) { return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN); return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN) && !isFromSource(source, AINPUT_SOURCE_STYLUS); } static ::base::TimeTicks toChromeTimestamp(nsecs_t eventTime) { Loading Loading @@ -367,6 +368,14 @@ void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs* args) { } void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) { ftl::StaticVector<NotifyMotionArgs, 2> processedArgs = mPreferStylusOverTouchBlocker.processMotion(*args); for (const NotifyMotionArgs& loopArgs : processedArgs) { notifyMotionInner(&loopArgs); } } void UnwantedInteractionBlocker::notifyMotionInner(const NotifyMotionArgs* args) { auto it = mPalmRejectors.find(args->deviceId); const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source); if (!sendToPalmRejector) { Loading Loading @@ -440,6 +449,8 @@ void UnwantedInteractionBlocker::notifyInputDevicesChanged( void UnwantedInteractionBlocker::dump(std::string& dump) { dump += "UnwantedInteractionBlocker:\n"; dump += " mPreferStylusOverTouchBlocker:\n"; dump += addPrefix(mPreferStylusOverTouchBlocker.dump(), " "); dump += StringPrintf(" mEnablePalmRejection: %s\n", toString(mEnablePalmRejection)); dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n", toString(isPalmRejectionEnabled())); Loading services/inputflinger/UnwantedInteractionBlocker.h +6 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_util.h" #include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h" #include "PreferStylusOverTouchBlocker.h" namespace android { // --- Functions for manipulation of event streams Loading Loading @@ -88,9 +90,13 @@ private: InputListenerInterface& mListener; const bool mEnablePalmRejection; // When stylus is down, ignore touch PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker; // Detect and reject unwanted palms on screen // Use a separate palm rejector for every touch device. std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors; // TODO(b/210159205): delete this when simultaneous stylus and touch is supported void notifyMotionInner(const NotifyMotionArgs* args); }; class SlotState { Loading Loading
services/inputflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ filegroup { srcs: [ "InputClassifier.cpp", "InputCommonConverter.cpp", "PreferStylusOverTouchBlocker.cpp", "UnwantedInteractionBlocker.cpp", "InputManager.cpp", ], Loading
services/inputflinger/PreferStylusOverTouchBlocker.cpp 0 → 100644 +107 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "PreferStylusOverTouchBlocker.h" #include <android-base/stringprintf.h> using android::base::StringPrintf; static const char* toString(bool value) { return value ? "true" : "false"; } namespace android { ftl::StaticVector<NotifyMotionArgs, 2> PreferStylusOverTouchBlocker::processMotion( const NotifyMotionArgs& args) { const bool isStylusEvent = isFromSource(args.source, AINPUT_SOURCE_STYLUS); if (isStylusEvent) { for (size_t i = 0; i < args.pointerCount; i++) { // Make sure we are canceling stylus pointers const int32_t toolType = args.pointerProperties[i].toolType; LOG_ALWAYS_FATAL_IF(toolType != AMOTION_EVENT_TOOL_TYPE_STYLUS && toolType != AMOTION_EVENT_TOOL_TYPE_ERASER, "The pointer %zu has toolType=%i, but the source is STYLUS. If " "simultaneous touch and stylus is supported, " "'PreferStylusOverTouchBlocker' should be disabled.", i, toolType); } } const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN; const bool isUpOrCancel = args.action == AMOTION_EVENT_ACTION_UP || args.action == AMOTION_EVENT_ACTION_CANCEL; if (isStylusEvent) { if (isDown) { // Reject all touch while stylus is down mIsStylusDown = true; if (mIsTouchDown && !mCurrentTouchIsCanceled) { // Cancel touch! mCurrentTouchIsCanceled = true; mLastTouchEvent.action = AMOTION_EVENT_ACTION_CANCEL; mLastTouchEvent.flags |= AMOTION_EVENT_FLAG_CANCELED; mLastTouchEvent.eventTime = systemTime(SYSTEM_TIME_MONOTONIC); return {mLastTouchEvent, args}; } } if (isUpOrCancel) { mIsStylusDown = false; } // Never drop stylus events return {args}; } const bool isTouchEvent = isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN) && !isStylusEvent; if (isTouchEvent) { if (mIsStylusDown) { mCurrentTouchIsCanceled = true; } // If we already canceled the current gesture, then continue to drop events from it, even if // the stylus has been lifted. if (mCurrentTouchIsCanceled) { if (isUpOrCancel) { mCurrentTouchIsCanceled = false; } return {}; } // Update state mLastTouchEvent = args; if (isDown) { mIsTouchDown = true; } if (isUpOrCancel) { mIsTouchDown = false; mCurrentTouchIsCanceled = false; } return {args}; } // Not a touch or stylus event return {args}; } std::string PreferStylusOverTouchBlocker::dump() { std::string out; out += StringPrintf("mIsTouchDown: %s\n", toString(mIsTouchDown)); out += StringPrintf("mIsStylusDown: %s\n", toString(mIsStylusDown)); out += StringPrintf("mLastTouchEvent: %s\n", mLastTouchEvent.dump().c_str()); out += StringPrintf("mCurrentTouchIsCanceled: %s\n", toString(mCurrentTouchIsCanceled)); return out; } } // namespace android
services/inputflinger/PreferStylusOverTouchBlocker.h 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <ftl/static_vector.h> #include <optional> #include "InputListener.h" namespace android { /** * When stylus is down, we ignore all touch. * TODO(b/210159205): delete this when simultaneous stylus and touch is supported */ class PreferStylusOverTouchBlocker { public: /** * Process the provided event and emit up to 2 events in response. * In the majority of cases, the returned result will just be the provided args (array with * only 1 element), unmodified. * * If the gesture should be blocked, the returned result may be: * * a) An empty array, if the current event should just be ignored completely * b) An array of 2 elements, containing an event with ACTION_CANCEL and the current event. * * bool is set to 'true'. * NotifyMotionArgs potentially contains an event that should be used to cancel the existing * gesture. * * If the event should not be blocked, bool contains 'false'. */ ftl::StaticVector<NotifyMotionArgs, 2> processMotion(const NotifyMotionArgs& args); std::string dump(); private: bool mIsTouchDown = false; bool mIsStylusDown = false; // Provide some default values for the stored MotionEvent to allow printint the event before // any real event is received. NotifyMotionArgs mLastTouchEvent{0 /*id*/, 0 /*eventTime*/, 0 /*readTime*/, 0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, 0 /*displayId*/, 0 /*policyFlags*/, 0 /*action*/, 0 /*actionButton*/, 0 /*flags*/, 0 /*metaState*/, 0 /*buttonState*/, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 0 /*pointerCount*/, nullptr /*properties*/, nullptr /*coords*/, 0. /*xPrecision*/, 0. /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, {}}; bool mCurrentTouchIsCanceled = false; }; } // namespace android No newline at end of file
services/inputflinger/UnwantedInteractionBlocker.cpp +12 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,8 @@ static std::string toLower(std::string s) { } static bool isFromTouchscreen(int32_t source) { return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN); return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN) && !isFromSource(source, AINPUT_SOURCE_STYLUS); } static ::base::TimeTicks toChromeTimestamp(nsecs_t eventTime) { Loading Loading @@ -367,6 +368,14 @@ void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs* args) { } void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) { ftl::StaticVector<NotifyMotionArgs, 2> processedArgs = mPreferStylusOverTouchBlocker.processMotion(*args); for (const NotifyMotionArgs& loopArgs : processedArgs) { notifyMotionInner(&loopArgs); } } void UnwantedInteractionBlocker::notifyMotionInner(const NotifyMotionArgs* args) { auto it = mPalmRejectors.find(args->deviceId); const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source); if (!sendToPalmRejector) { Loading Loading @@ -440,6 +449,8 @@ void UnwantedInteractionBlocker::notifyInputDevicesChanged( void UnwantedInteractionBlocker::dump(std::string& dump) { dump += "UnwantedInteractionBlocker:\n"; dump += " mPreferStylusOverTouchBlocker:\n"; dump += addPrefix(mPreferStylusOverTouchBlocker.dump(), " "); dump += StringPrintf(" mEnablePalmRejection: %s\n", toString(mEnablePalmRejection)); dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n", toString(isPalmRejectionEnabled())); Loading
services/inputflinger/UnwantedInteractionBlocker.h +6 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_util.h" #include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h" #include "PreferStylusOverTouchBlocker.h" namespace android { // --- Functions for manipulation of event streams Loading Loading @@ -88,9 +90,13 @@ private: InputListenerInterface& mListener; const bool mEnablePalmRejection; // When stylus is down, ignore touch PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker; // Detect and reject unwanted palms on screen // Use a separate palm rejector for every touch device. std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors; // TODO(b/210159205): delete this when simultaneous stylus and touch is supported void notifyMotionInner(const NotifyMotionArgs* args); }; class SlotState { Loading