From 3720ed06a4be83f6cec4ad7233ed6b6773fb7403 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 8 Aug 2018 16:08:27 -0700 Subject: Implement Parcelling functions for InputWindowInfo In preparation for parcelling across the SurfaceControl interface. As a dependency we move the parcelling of InputChannels from frameworks/base JNI code in to InputChannel.h. Bug: 80101428 Bug: 113136004 Bug: 111440400 Test: None Change-Id: Ib27f03282e9872274b834bb00737fd351e7a1b30 --- libs/input/InputWindow.cpp | 159 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 libs/input/InputWindow.cpp (limited to 'libs/input/InputWindow.cpp') diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp new file mode 100644 index 0000000000..f94faba99b --- /dev/null +++ b/libs/input/InputWindow.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2011 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. + */ + +#define LOG_TAG "InputWindow" +#define LOG_NDEBUG 0 + +#include +#include +#include + +#include + +#include +#include + +namespace android { + +// --- InputWindowInfo --- +void InputWindowInfo::addTouchableRegion(const Rect& region) { + touchableRegion.orSelf(region); +} + +bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { + return touchableRegion.contains(x,y); +} + +bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { + return x >= frameLeft && x < frameRight + && y >= frameTop && y < frameBottom; +} + +bool InputWindowInfo::isTrustedOverlay() const { + return layoutParamsType == TYPE_INPUT_METHOD + || layoutParamsType == TYPE_INPUT_METHOD_DIALOG + || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY + || layoutParamsType == TYPE_STATUS_BAR + || layoutParamsType == TYPE_NAVIGATION_BAR + || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL + || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY + || layoutParamsType == TYPE_DOCK_DIVIDER + || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY + || layoutParamsType == TYPE_INPUT_CONSUMER; +} + +bool InputWindowInfo::supportsSplitTouch() const { + return layoutParamsFlags & FLAG_SPLIT_TOUCH; +} + +bool InputWindowInfo::overlaps(const InputWindowInfo* other) const { + return frameLeft < other->frameRight && frameRight > other->frameLeft + && frameTop < other->frameBottom && frameBottom > other->frameTop; +} + +status_t InputWindowInfo::write(Parcel& output) const { + if (inputChannel == nullptr) { + output.writeInt32(0); + return OK; + } + output.writeInt32(1); + status_t s = inputChannel->write(output); + if (s != OK) return s; + + output.writeString8(String8(name.c_str())); + output.writeInt32(layoutParamsFlags); + output.writeInt32(layoutParamsType); + output.writeInt64(dispatchingTimeout); + output.writeInt32(frameLeft); + output.writeInt32(frameTop); + output.writeInt32(frameRight); + output.writeInt32(frameBottom); + output.writeFloat(scaleFactor); + output.writeBool(visible); + output.writeBool(canReceiveKeys); + output.writeBool(hasFocus); + output.writeBool(hasWallpaper); + output.writeBool(paused); + output.writeInt32(layer); + output.writeInt32(ownerPid); + output.writeInt32(ownerUid); + output.writeInt32(inputFeatures); + output.writeInt32(displayId); + output.write(touchableRegion); + + return OK; +} + +InputWindowInfo InputWindowInfo::read(const Parcel& from) { + InputWindowInfo ret; + + if (from.readInt32() == 0) { + return ret; + + } + sp inputChannel = new InputChannel(); + status_t s = inputChannel->read(from); + if (s != OK) { + return ret; + } + + ret.inputChannel = inputChannel; + ret.name = from.readString8().c_str(); + ret.layoutParamsFlags = from.readInt32(); + ret.layoutParamsType = from.readInt32(); + ret.dispatchingTimeout = from.readInt64(); + ret.frameLeft = from.readInt32(); + ret.frameTop = from.readInt32(); + ret.frameRight = from.readInt32(); + ret.frameBottom = from.readInt32(); + ret.scaleFactor = from.readFloat(); + ret.visible = from.readBool(); + ret.canReceiveKeys = from.readBool(); + ret.hasFocus = from.readBool(); + ret.hasWallpaper = from.readBool(); + ret.paused = from.readBool(); + ret.layer = from.readInt32(); + ret.ownerPid = from.readInt32(); + ret.ownerUid = from.readInt32(); + ret.inputFeatures = from.readInt32(); + ret.displayId = from.readInt32(); + from.read(ret.touchableRegion); + + return ret; +} + +// --- InputWindowHandle --- + +InputWindowHandle::InputWindowHandle(const sp& inputApplicationHandle) : + inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) { +} + +InputWindowHandle::~InputWindowHandle() { + delete mInfo; +} + +void InputWindowHandle::releaseInfo() { + if (mInfo) { + delete mInfo; + mInfo = nullptr; + } +} + +sp InputWindowHandle::getInputChannel() const { + return mInfo ? mInfo->inputChannel : nullptr; +} + +} // namespace android -- cgit v1.2.3-59-g8ed1b From 3b413f202de8a0bde465cd92d0265eb98f5a479f Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Fri, 26 Oct 2018 18:05:34 +0800 Subject: Make InputWindowInfo as a part of InputWindowHandle (1/2) All over InputDispatcher, we are accessing InputWindowInfo from InputWindowHandle through the api getInfo(). It's dangerous without checking the result is null. - To replace allocated mInfo in updateInfo(), make it as an object member variable of InputWindowHandle. - Change releaseInfo to releaseChannel to release input channel immediately. - Add displayId information for logs so we can find out the problems should belong to which display. Bug: 112616659 Test: atest inputflinger_tests Test: Manually enable debug logs Change-Id: I5770f296e3feab4919fe775bab20ef6346f05295 --- include/input/InputWindow.h | 12 ++-- libs/input/InputWindow.cpp | 12 ++-- services/inputflinger/InputDispatcher.cpp | 77 ++++++++++++---------- .../inputflinger/tests/InputDispatcher_test.cpp | 73 +++++++++++++------- 4 files changed, 103 insertions(+), 71 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 7c284ddaf6..918b9e18e3 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -168,17 +168,17 @@ public: const sp inputApplicationHandle; inline const InputWindowInfo* getInfo() const { - return mInfo; + return &mInfo; } sp getInputChannel() const; inline std::string getName() const { - return mInfo ? mInfo->name : ""; + return mInfo.inputChannel ? mInfo.name : ""; } inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { - return mInfo ? mInfo->dispatchingTimeout : defaultValue; + return mInfo.inputChannel? mInfo.dispatchingTimeout : defaultValue; } /** @@ -193,16 +193,16 @@ public: virtual bool updateInfo() = 0; /** - * Releases the storage used by the associated information when it is + * Releases the channel used by the associated information when it is * no longer needed. */ - void releaseInfo(); + void releaseChannel(); protected: explicit InputWindowHandle(const sp& inputApplicationHandle); virtual ~InputWindowHandle(); - InputWindowInfo* mInfo; + InputWindowInfo mInfo; }; } // namespace android diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index f94faba99b..6968661a16 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -138,22 +138,18 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { // --- InputWindowHandle --- InputWindowHandle::InputWindowHandle(const sp& inputApplicationHandle) : - inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) { + inputApplicationHandle(inputApplicationHandle) { } InputWindowHandle::~InputWindowHandle() { - delete mInfo; } -void InputWindowHandle::releaseInfo() { - if (mInfo) { - delete mInfo; - mInfo = nullptr; - } +void InputWindowHandle::releaseChannel() { + mInfo.inputChannel.clear(); } sp InputWindowHandle::getInputChannel() const { - return mInfo ? mInfo->inputChannel : nullptr; + return mInfo.inputChannel; } } // namespace android diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 2e984d9ca9..3f39afd8b0 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -864,11 +864,11 @@ void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyE #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", " "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, " - "metaState=0x%x, repeatCount=%d, downTime=%" PRId64, + "metaState=0x%x, repeatCount=%d, downTime=%" PRId64 ", displayId=%" PRId32, prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, - entry->repeatCount, entry->downTime); + entry->repeatCount, entry->downTime, entry->displayId); #endif } @@ -940,13 +940,13 @@ void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const M ", policyFlags=0x%x, " "action=0x%x, actionButton=0x%x, flags=0x%x, " "metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64", displayId=%" PRId32, prefix, entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags, entry->action, entry->actionButton, entry->flags, entry->metaState, entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, - entry->downTime); + entry->downTime, entry->displayId); for (uint32_t i = 0; i < entry->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " @@ -1168,7 +1168,8 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, goto Unresponsive; } - ALOGI("Dropping event because there is no focused window or focused application."); + ALOGI("Dropping event because there is no focused window or focused application in display " + "%" PRId32 ".", displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } @@ -1254,7 +1255,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; if (switchedDevice && mTempTouchState.down && !down && !isHoverAction) { #if DEBUG_FOCUS - ALOGD("Dropping event because a pointer for a different device is already down."); + ALOGD("Dropping event because a pointer for a different device is already down " + "in display %" PRId32, displayId); #endif // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_FAILED; @@ -1270,7 +1272,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, isSplit = false; } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) { #if DEBUG_FOCUS - ALOGI("Dropping move event because a pointer for a different device is already active."); + ALOGI("Dropping move event because a pointer for a different device is already active " + "in display %" PRId32, displayId); #endif // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; @@ -1335,7 +1338,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // Try to assign the pointer to the first foreground window we find, if there is one. newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); if (newTouchedWindowHandle == nullptr) { - ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y); + ALOGI("Dropping event because there is no touchable window at (%d, %d) in display " + "%" PRId32 ".", x, y, displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } @@ -1373,7 +1377,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (! mTempTouchState.down) { #if DEBUG_FOCUS ALOGD("Dropping event because the pointer is not down or we previously " - "dropped the pointer down event."); + "dropped the pointer down event in display %" PRId32, displayId); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; @@ -1393,9 +1397,10 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (oldTouchedWindowHandle != newTouchedWindowHandle && newTouchedWindowHandle != nullptr) { #if DEBUG_FOCUS - ALOGD("Touch is slipping out of window %s into window %s.", + ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32, oldTouchedWindowHandle->getName().c_str(), - newTouchedWindowHandle->getName().c_str()); + newTouchedWindowHandle->getName().c_str(), + displayId); #endif // Make a slippery exit from the old window. mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, @@ -1464,7 +1469,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } if (! haveForegroundWindow) { #if DEBUG_FOCUS - ALOGD("Dropping event because there is no touched foreground window to receive it."); + ALOGD("Dropping event because there is no touched foreground window in display %" PRId32 + " to receive it.", displayId); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; @@ -1689,7 +1695,7 @@ void InputDispatcher::addMonitoringTargetsLocked(Vector& inputTarge } else { // If there is no monitor channel registered or all monitor channel unregistered, // the display can't detect the extra system gesture by a copy of input events. - ALOGW("There is no monitor channel found in display=%" PRId32, displayId); + ALOGW("There is no monitor channel found in display %" PRId32, displayId); } } @@ -2533,10 +2539,11 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyKey - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, " - "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64, + "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64 + ", displayId=%" PRId32, args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, args->action, args->flags, args->keyCode, args->scanCode, - args->metaState, args->downTime); + args->metaState, args->downTime, args->displayId); #endif if (!validateKeyEvent(args->action)) { return; @@ -2611,10 +2618,10 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", policyFlags=0x%x, " "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, - args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", displayId=%" PRId32 + , args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, args->action, args->actionButton, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); + args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, args->displayId); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " "x=%f, y=%f, pressure=%f, size=%f, " @@ -3013,9 +3020,10 @@ bool InputDispatcher::hasWindowHandleLocked( for (size_t i = 0; i < numWindows; i++) { if (windowHandles.itemAt(i) == windowHandle) { if (windowHandle->getInfo()->displayId != it.first) { - ALOGE("Found window %s in display %d, but it should belong to display %d", - windowHandle->getName().c_str(), it.first, - windowHandle->getInfo()->displayId); + ALOGE("Found window %s in display %" PRId32 + ", but it should belong to display %" PRId32, + windowHandle->getName().c_str(), it.first, + windowHandle->getInfo()->displayId); } return true; } @@ -3034,7 +3042,7 @@ bool InputDispatcher::hasWindowHandleLocked( void InputDispatcher::setInputWindows(const Vector>& inputWindowHandles, int32_t displayId) { #if DEBUG_FOCUS - ALOGD("setInputWindows"); + ALOGD("setInputWindows displayId=%" PRId32, displayId); #endif { // acquire lock AutoMutex _l(mLock); @@ -3085,8 +3093,8 @@ void InputDispatcher::setInputWindows(const Vector>& input if (oldFocusedWindowHandle != newFocusedWindowHandle) { if (oldFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS - ALOGD("Focus left window: %s", - oldFocusedWindowHandle->getName().c_str()); + ALOGD("Focus left window: %s in display %" PRId32, + oldFocusedWindowHandle->getName().c_str(), displayId); #endif sp focusedInputChannel = oldFocusedWindowHandle->getInputChannel(); if (focusedInputChannel != nullptr) { @@ -3099,8 +3107,8 @@ void InputDispatcher::setInputWindows(const Vector>& input } if (newFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS - ALOGD("Focus entered window: %s", - newFocusedWindowHandle->getName().c_str()); + ALOGD("Focus entered window: %s in display %" PRId32, + newFocusedWindowHandle->getName().c_str(), displayId); #endif mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle; } @@ -3113,8 +3121,8 @@ void InputDispatcher::setInputWindows(const Vector>& input TouchedWindow& touchedWindow = state.windows.editItemAt(i); if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS - ALOGD("Touched window was removed: %s", - touchedWindow.windowHandle->getName().c_str()); + ALOGD("Touched window was removed: %s in display %" PRId32, + touchedWindow.windowHandle->getName().c_str(), displayId); #endif sp touchedInputChannel = touchedWindow.windowHandle->getInputChannel(); @@ -3142,7 +3150,7 @@ void InputDispatcher::setInputWindows(const Vector>& input #if DEBUG_FOCUS ALOGD("Window went away: %s", oldWindowHandle->getName().c_str()); #endif - oldWindowHandle->releaseInfo(); + oldWindowHandle->releaseChannel(); } } } // release lock @@ -3154,7 +3162,7 @@ void InputDispatcher::setInputWindows(const Vector>& input void InputDispatcher::setFocusedApplication( int32_t displayId, const sp& inputApplicationHandle) { #if DEBUG_FOCUS - ALOGD("setFocusedApplication"); + ALOGD("setFocusedApplication displayId=%" PRId32, displayId); #endif { // acquire lock AutoMutex _l(mLock); @@ -3469,7 +3477,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { if (!mWindowHandlesByDisplay.empty()) { for (auto& it : mWindowHandlesByDisplay) { const Vector> windowHandles = it.second; - dump += StringPrintf(INDENT "Display: %d\n", it.first); + dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first); if (!windowHandles.isEmpty()) { dump += INDENT2 "Windows:\n"; for (size_t i = 0; i < windowHandles.size(); i++) { @@ -3509,7 +3517,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { if (!mMonitoringChannelsByDisplay.empty()) { for (auto& it : mMonitoringChannelsByDisplay) { const Vector>& monitoringChannels = it.second; - dump += INDENT "MonitoringChannels in Display %d:\n"; + dump += StringPrintf(INDENT "MonitoringChannels in display %" PRId32 ":\n", it.first); const size_t numChannels = monitoringChannels.size(); for (size_t i = 0; i < numChannels; i++) { const sp& channel = monitoringChannels[i]; @@ -3737,6 +3745,10 @@ void InputDispatcher::removeMonitorChannelLocked(const sp& inputCh } ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputChannel) { + if (!inputChannel) { + return -1; + } + ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd()); if (connectionIndex >= 0) { sp connection = mConnectionsByFd.valueAt(connectionIndex); @@ -3744,7 +3756,6 @@ ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputC return connectionIndex; } } - return -1; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index c6eaf9f048..066c143d51 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -370,30 +370,27 @@ public: } virtual bool updateInfo() { - if (!mInfo) { - mInfo = new InputWindowInfo(); - } - mInfo->inputChannel = mServerChannel; - mInfo->name = mName; - mInfo->layoutParamsFlags = 0; - mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION; - mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT; - mInfo->frameLeft = 0; - mInfo->frameTop = 0; - mInfo->frameRight = WIDTH; - mInfo->frameBottom = HEIGHT; - mInfo->scaleFactor = 1.0; - mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT)); - mInfo->visible = true; - mInfo->canReceiveKeys = true; - mInfo->hasFocus = mFocused; - mInfo->hasWallpaper = false; - mInfo->paused = false; - mInfo->layer = 0; - mInfo->ownerPid = INJECTOR_PID; - mInfo->ownerUid = INJECTOR_UID; - mInfo->inputFeatures = 0; - mInfo->displayId = mDisplayId; + mInfo.inputChannel = mServerChannel; + mInfo.name = mName; + mInfo.layoutParamsFlags = 0; + mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION; + mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; + mInfo.frameLeft = 0; + mInfo.frameTop = 0; + mInfo.frameRight = WIDTH; + mInfo.frameBottom = HEIGHT; + mInfo.scaleFactor = 1.0; + mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT)); + mInfo.visible = true; + mInfo.canReceiveKeys = true; + mInfo.hasFocus = mFocused; + mInfo.hasWallpaper = false; + mInfo.paused = false; + mInfo.layer = 0; + mInfo.ownerPid = INJECTOR_PID; + mInfo.ownerUid = INJECTOR_UID; + mInfo.inputFeatures = 0; + mInfo.displayId = mDisplayId; return true; } @@ -529,6 +526,34 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) { windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE); } +TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) { + sp application = new FakeApplicationHandle(); + + sp windowTop = new FakeWindowHandle(application, mDispatcher, "Top", + ADISPLAY_ID_DEFAULT); + sp windowSecond = new FakeWindowHandle(application, mDispatcher, "Second", + ADISPLAY_ID_DEFAULT); + + windowTop->setFocus(); + + Vector> inputWindowHandles; + inputWindowHandles.add(windowTop); + inputWindowHandles.add(windowSecond); + + mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT); + + // Release channel for window is no longer valid. + windowTop->releaseChannel(); + + // Test inject a motion down, should timeout because of no target channel. + ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher)) + << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT"; + + // Top window is invalid, so it should not receive any input event. + windowTop->assertNoEvents(); + windowSecond->assertNoEvents(); +} + /* Test InputDispatcher for MultiDisplay */ class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { public: -- cgit v1.2.3-59-g8ed1b From 1cc78672c860d8af8dbb818bd44342697054866d Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 31 Jul 2018 14:25:57 -0700 Subject: InputFlinger: Receive setInputWindows over IPC Plumbing to expose the InputManager object as an InputFlinger service with a single setInputWindows method. Bug: 80101428 Bug: 113136004 Bug: 111440400 Change-Id: I6e63a7e251711993334d930d2b95352e6cba031e --- include/input/IInputFlinger.h | 7 +++++- include/input/InputWindow.h | 3 +++ libs/input/Android.bp | 4 ++-- libs/input/IInputFlinger.cpp | 25 +++++++++++++++------ libs/input/InputWindow.cpp | 4 ++++ services/inputflinger/Android.bp | 1 + services/inputflinger/InputManager.cpp | 36 +++++++++++++++++++++++++++++++ services/inputflinger/InputManager.h | 6 +++++- services/inputflinger/host/Android.bp | 8 ++++++- services/inputflinger/host/InputFlinger.h | 1 + 10 files changed, 83 insertions(+), 12 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h index 11bb7215d6..1ef8986267 100644 --- a/include/input/IInputFlinger.h +++ b/include/input/IInputFlinger.h @@ -22,6 +22,9 @@ #include +#include +#include + namespace android { /* @@ -31,6 +34,8 @@ namespace android { class IInputFlinger : public IInterface { public: DECLARE_META_INTERFACE(InputFlinger) + + virtual void setInputWindows(const Vector& inputHandles) = 0; }; @@ -40,7 +45,7 @@ public: class BnInputFlinger : public BnInterface { public: enum { - DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 918b9e18e3..9e3d334f7f 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -33,6 +33,9 @@ class Parcel; * Describes the properties of a window that can receive input. */ struct InputWindowInfo { + InputWindowInfo() = default; + InputWindowInfo(const Parcel& from); + // Window flags from WindowManager.LayoutParams enum { FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 72558a6d91..8cb8649dff 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -43,12 +43,12 @@ cc_library { target: { android: { srcs: [ - "IInputFlinger.cpp", "InputTransport.cpp", "VelocityControl.cpp", "VelocityTracker.cpp", "InputApplication.cpp", - "InputWindow.cpp" + "InputWindow.cpp", + "IInputFlinger.cpp" ], shared_libs: [ diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp index 003e73dae6..47a2c0c347 100644 --- a/libs/input/IInputFlinger.cpp +++ b/libs/input/IInputFlinger.cpp @@ -23,7 +23,6 @@ #include - namespace android { class BpInputFlinger : public BpInterface { @@ -31,23 +30,35 @@ public: explicit BpInputFlinger(const sp& impl) : BpInterface(impl) { } - virtual status_t doSomething() { + virtual void setInputWindows(const Vector& inputInfo) { Parcel data, reply; data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); - remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply); - return reply.readInt32(); + + data.writeUint32(static_cast(inputInfo.size())); + for (const auto& info : inputInfo) { + info.write(data); + } + remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply); } }; IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger"); - status_t BnInputFlinger::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { - case DO_SOMETHING_TRANSACTION: { + case SET_INPUT_WINDOWS_TRANSACTION: { CHECK_INTERFACE(IInputFlinger, data, reply); - reply->writeInt32(0); + size_t count = data.readUint32(); + if (count > data.dataSize()) { + return BAD_VALUE; + } + Vector handles; + handles.setCapacity(count); + for (size_t i = 0; i < count; i++) { + handles.add(InputWindowInfo(data)); + } + setInputWindows(handles); break; } default: diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index 6968661a16..f82437e1bf 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -135,6 +135,10 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { return ret; } +InputWindowInfo::InputWindowInfo(const Parcel& from) { + *this = read(from); +} + // --- InputWindowHandle --- InputWindowHandle::InputWindowHandle(const sp& inputApplicationHandle) : diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 9a65452f60..7812cb2a61 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -35,6 +35,7 @@ cc_library_shared { "libutils", "libui", "libhardware_legacy", + "libutils" ], cflags: [ diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index 519faa6b5c..40ca6a7d6d 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -21,6 +21,7 @@ #include "InputManager.h" #include +#include namespace android { @@ -90,4 +91,39 @@ sp InputManager::getDispatcher() { return mDispatcher; } +class BinderApplicationHandle : public InputApplicationHandle { +public: + BinderApplicationHandle() = default; + + bool updateInfo() override { + return true; + } +}; + +class BinderWindowHandle : public InputWindowHandle { +public: + BinderWindowHandle(const InputWindowInfo& info) : + InputWindowHandle(new BinderApplicationHandle()) { + + mInfo = info; + } + + bool updateInfo() override { + return true; + } +}; + +void InputManager::setInputWindows(const Vector& infos) { + std::unordered_map>> handlesPerDisplay; + + Vector> handles; + for (const auto& info : infos) { + handlesPerDisplay.emplace(info.displayId, Vector>()); + handlesPerDisplay[info.displayId].add(new BinderWindowHandle(info)); + } + for (auto const& i : handlesPerDisplay) { + mDispatcher->setInputWindows(i.second, i.first); + } +} + } // namespace android diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index 92e0af21c3..d0e4cb02be 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -27,6 +27,8 @@ #include #include + +#include #include #include #include @@ -72,7 +74,7 @@ public: virtual sp getDispatcher() = 0; }; -class InputManager : public InputManagerInterface { +class InputManager : public InputManagerInterface, public BnInputFlinger { protected: virtual ~InputManager(); @@ -93,6 +95,8 @@ public: virtual sp getReader(); virtual sp getDispatcher(); + virtual void setInputWindows(const Vector& handles); + private: sp mReader; sp mReaderThread; diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp index 775dbdc658..0e48f246b2 100644 --- a/services/inputflinger/host/Android.bp +++ b/services/inputflinger/host/Android.bp @@ -30,6 +30,9 @@ cc_library_shared { "libutils", "libhardware", ], + static_libs: [ + "libarect", + ], cflags: [ "-Wall", @@ -54,7 +57,10 @@ cc_binary { shared_libs: [ "libbinder", "libinputflingerhost", - "libutils", + "libutils" + ], + static_libs: [ + "libarect", ], init_rc: ["inputflinger.rc"], diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h index 39e69e5efc..15ca7b3c24 100644 --- a/services/inputflinger/host/InputFlinger.h +++ b/services/inputflinger/host/InputFlinger.h @@ -39,6 +39,7 @@ public: InputFlinger() ANDROID_API; virtual status_t dump(int fd, const Vector& args); + void setInputWindows(const Vector&) {} private: virtual ~InputFlinger(); -- cgit v1.2.3-59-g8ed1b From 5c8a026133d5bbcb6f416952937a7a810bccc8b1 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 3 Oct 2018 16:30:44 -0700 Subject: Replace InputWindowInfo#inputChannel with an IBinder token. The IBinder token is now being used as the UUID for InputWindows. We can pass it around without the channel to avoid unnecessary FD parcelling, duping, and other juggling. Test: Existing tests pass. Bug: 80101428 Bug: 113136004 Bug: 111440400 Change-Id: I8eba3fa05f249b7dfcb5c3d9817241cbfe9ab76c --- include/input/InputWindow.h | 8 ++--- libs/gui/tests/EndToEndNativeInputTest.cpp | 2 +- libs/input/InputWindow.cpp | 19 +++++----- libs/input/tests/InputWindow_test.cpp | 15 ++++---- services/inputflinger/InputDispatcher.cpp | 41 +++++++++++++++------- services/inputflinger/InputDispatcher.h | 9 +++++ .../inputflinger/tests/InputDispatcher_test.cpp | 4 +-- services/surfaceflinger/Layer.cpp | 2 +- 8 files changed, 61 insertions(+), 39 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 9e3d334f7f..6164aa6f09 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -117,7 +117,7 @@ struct InputWindowInfo { INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004, }; - sp inputChannel; + sp token; std::string name; int32_t layoutParamsFlags; int32_t layoutParamsType; @@ -174,14 +174,14 @@ public: return &mInfo; } - sp getInputChannel() const; + sp getToken() const; inline std::string getName() const { - return mInfo.inputChannel ? mInfo.name : ""; + return mInfo.token ? mInfo.name : ""; } inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { - return mInfo.inputChannel? mInfo.dispatchingTimeout : defaultValue; + return mInfo.token ? mInfo.dispatchingTimeout : defaultValue; } /** diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 2f165c4131..7b727047d1 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -135,7 +135,7 @@ private: } void populateInputInfo(int width, int height) { - mInputInfo.inputChannel = mServerChannel; + mInputInfo.token = mServerChannel->getToken(); mInputInfo.name = "Test info"; mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL; mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION; diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index f82437e1bf..96646dc6f8 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -65,12 +65,12 @@ bool InputWindowInfo::overlaps(const InputWindowInfo* other) const { } status_t InputWindowInfo::write(Parcel& output) const { - if (inputChannel == nullptr) { + if (token == nullptr) { output.writeInt32(0); return OK; } output.writeInt32(1); - status_t s = inputChannel->write(output); + status_t s = output.writeStrongBinder(token); if (s != OK) return s; output.writeString8(String8(name.c_str())); @@ -102,15 +102,14 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { if (from.readInt32() == 0) { return ret; - } - sp inputChannel = new InputChannel(); - status_t s = inputChannel->read(from); - if (s != OK) { + + sp token = from.readStrongBinder(); + if (token == nullptr) { return ret; } - ret.inputChannel = inputChannel; + ret.token = token; ret.name = from.readString8().c_str(); ret.layoutParamsFlags = from.readInt32(); ret.layoutParamsType = from.readInt32(); @@ -149,11 +148,11 @@ InputWindowHandle::~InputWindowHandle() { } void InputWindowHandle::releaseChannel() { - mInfo.inputChannel.clear(); + mInfo.token.clear(); } -sp InputWindowHandle::getInputChannel() const { - return mInfo.inputChannel; +sp InputWindowHandle::getToken() const { + return mInfo.token; } } // namespace android diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp index 39ad26e8c1..ea98f8a302 100644 --- a/libs/input/tests/InputWindow_test.cpp +++ b/libs/input/tests/InputWindow_test.cpp @@ -16,6 +16,7 @@ #include +#include #include #include @@ -24,24 +25,20 @@ namespace android { namespace test { -TEST(InputWindowInfo, ParcellingWithoutChannel) { +TEST(InputWindowInfo, ParcellingWithoutToken) { InputWindowInfo i; - i.inputChannel = nullptr; + i.token = nullptr; Parcel p; ASSERT_EQ(OK, i.write(p)); p.setDataPosition(0); InputWindowInfo i2 = InputWindowInfo::read(p); - ASSERT_TRUE(i2.inputChannel == nullptr); + ASSERT_TRUE(i2.token == nullptr); } TEST(InputWindowInfo, Parcelling) { - sp channel, junkChannel; - status_t result = InputChannel::openInputChannelPair("name", channel, junkChannel); - ASSERT_EQ(OK, result) << "openInputChannelPair should have returned valid channels"; - InputWindowInfo i; - i.inputChannel = channel; + i.token = new BBinder(); i.name = "Foobar"; i.layoutParamsFlags = 7; i.layoutParamsType = 39; @@ -67,7 +64,7 @@ TEST(InputWindowInfo, Parcelling) { p.setDataPosition(0); InputWindowInfo i2 = InputWindowInfo::read(p); - ASSERT_EQ(i.inputChannel->getName(), i2.inputChannel->getName()); + ASSERT_EQ(i.token, i2.token); ASSERT_EQ(i.name, i2.name); ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags); ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType); diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 0c9e04bc18..e0082a5a95 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -819,7 +819,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, sp focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry)); if (focusedWindowHandle != nullptr) { - commandEntry->inputChannel = focusedWindowHandle->getInputChannel(); + commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken()); } commandEntry->keyEntry = entry; entry->refCount += 1; @@ -1666,7 +1666,7 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowH const InputWindowInfo* windowInfo = windowHandle->getInfo(); InputTarget& target = inputTargets.editTop(); - target.inputChannel = windowInfo->inputChannel; + target.inputChannel = getInputChannelLocked(windowHandle->getToken()); target.flags = targetFlags; target.xOffset = - windowInfo->frameLeft; target.yOffset = - windowInfo->frameTop; @@ -1773,7 +1773,8 @@ std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentT } // If the window's connection is not registered then keep waiting. - ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel()); + ssize_t connectionIndex = getConnectionIndexLocked( + getInputChannelLocked(windowHandle->getToken())); if (connectionIndex < 0) { return StringPrintf("Waiting because the %s window's input channel is not " "registered with the input dispatcher. The window may be in the process " @@ -3004,7 +3005,7 @@ sp InputDispatcher::getWindowHandleLocked( size_t numWindows = windowHandles.size(); for (size_t i = 0; i < numWindows; i++) { const sp& windowHandle = windowHandles.itemAt(i); - if (windowHandle->getInputChannel() == inputChannel) { + if (windowHandle->getToken() == inputChannel->getToken()) { return windowHandle; } } @@ -3018,8 +3019,8 @@ bool InputDispatcher::hasWindowHandleLocked( const Vector> windowHandles = it.second; size_t numWindows = windowHandles.size(); for (size_t i = 0; i < numWindows; i++) { - if (windowHandles.itemAt(i)->getInputChannel()->getToken() - == windowHandle->getInputChannel()->getToken()) { + if (windowHandles.itemAt(i)->getToken() + == windowHandle->getToken()) { if (windowHandle->getInfo()->displayId != it.first) { ALOGE("Found window %s in display %" PRId32 ", but it should belong to display %" PRId32, @@ -3033,6 +3034,14 @@ bool InputDispatcher::hasWindowHandleLocked( return false; } +sp InputDispatcher::getInputChannelLocked(const sp& token) const { + size_t count = mInputChannelsByToken.count(token); + if (count == 0) { + return nullptr; + } + return mInputChannelsByToken.at(token); +} + /** * Called from InputManagerService, update window handle list by displayId that can receive input. * A window handle contains information about InputChannel, Touch Region, Types, Focused,... @@ -3061,7 +3070,9 @@ void InputDispatcher::setInputWindows(const Vector>& input size_t numWindows = inputWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { const sp& windowHandle = inputWindowHandles.itemAt(i); - if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) { + if (!windowHandle->updateInfo() || getInputChannelLocked(windowHandle->getToken()) == nullptr) { + ALOGE("Window handle %s has no registered input channel", + windowHandle->getName().c_str()); continue; } @@ -3097,7 +3108,8 @@ void InputDispatcher::setInputWindows(const Vector>& input ALOGD("Focus left window: %s in display %" PRId32, oldFocusedWindowHandle->getName().c_str(), displayId); #endif - sp focusedInputChannel = oldFocusedWindowHandle->getInputChannel(); + sp focusedInputChannel = getInputChannelLocked( + oldFocusedWindowHandle->getToken()); if (focusedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, "focus left window"); @@ -3126,7 +3138,7 @@ void InputDispatcher::setInputWindows(const Vector>& input touchedWindow.windowHandle->getName().c_str(), displayId); #endif sp touchedInputChannel = - touchedWindow.windowHandle->getInputChannel(); + getInputChannelLocked(touchedWindow.windowHandle->getToken()); if (touchedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "touched window was removed"); @@ -3214,7 +3226,8 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) { sp oldFocusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId); if (oldFocusedWindowHandle != nullptr) { - sp inputChannel = oldFocusedWindowHandle->getInputChannel(); + sp inputChannel = + getInputChannelLocked(oldFocusedWindowHandle->getToken()); if (inputChannel != nullptr) { CancelationOptions options( CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS, @@ -3667,6 +3680,7 @@ status_t InputDispatcher::registerInputChannel(const sp& inputChan int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); + mInputChannelsByToken[inputChannel->getToken()] = inputChannel; // Store monitor channel by displayId. if (monitor) { @@ -3715,6 +3729,8 @@ status_t InputDispatcher::unregisterInputChannelLocked(const sp& i sp connection = mConnectionsByFd.valueAt(connectionIndex); mConnectionsByFd.removeItemsAt(connectionIndex); + mInputChannelsByToken.erase(inputChannel->getToken()); + if (connection->monitor) { removeMonitorChannelLocked(inputChannel); } @@ -3812,7 +3828,8 @@ void InputDispatcher::onANRLocked( CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyANRLockedInterruptible); commandEntry->inputApplicationHandle = applicationHandle; - commandEntry->inputChannel = windowHandle != nullptr ? windowHandle->getInputChannel() : nullptr; + commandEntry->inputChannel = windowHandle != nullptr ? + getInputChannelLocked(windowHandle->getToken()) : nullptr; commandEntry->reason = reason; } @@ -4847,7 +4864,7 @@ void InputDispatcher::TouchState::removeWindow(const sp& wind void InputDispatcher::TouchState::removeWindowByToken(const sp& token) { for (size_t i = 0; i < windows.size(); i++) { - if (windows.itemAt(i).windowHandle->getInputChannel()->getToken() == token) { + if (windows.itemAt(i).windowHandle->getToken() == token) { windows.removeAt(i); return; } diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 5016082958..38c7b45c59 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -916,6 +917,13 @@ private: // All registered connections mapped by channel file descriptor. KeyedVector > mConnectionsByFd; + struct IBinderHash { + std::size_t operator()(const sp& b) const { + return std::hash{}(b.get()); + } + }; + std::unordered_map, sp, IBinderHash> mInputChannelsByToken; + ssize_t getConnectionIndexLocked(const sp& inputChannel); // Input channels that will receive a copy of all input events sent to the provided display. @@ -979,6 +987,7 @@ private: // Get window handles by display, return an empty vector if not found. Vector> getWindowHandlesLocked(int32_t displayId) const; sp getWindowHandleLocked(const sp& inputChannel) const; + sp getInputChannelLocked(const sp& windowToken) const; bool hasWindowHandleLocked(const sp& windowHandle) const; // Focus tracking for keys, trackball, etc. diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index e860db59c4..26adcdd8a9 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -338,7 +338,6 @@ protected: const std::string name, int32_t displayId) : mDispatcher(dispatcher), mName(name), mDisplayId(displayId) { InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel); - mConsumer = new InputConsumer(mClientChannel); } @@ -352,6 +351,7 @@ protected: sp mDispatcher; sp mServerChannel, mClientChannel; + sp mToken; InputConsumer *mConsumer; PreallocatedInputEventFactory mEventFactory; @@ -374,7 +374,7 @@ public: } virtual bool updateInfo() { - mInfo.inputChannel = mServerChannel; + mInfo.token = mServerChannel->getToken(); mInfo.name = mName; mInfo.layoutParamsFlags = 0; mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d9ec44a03e..3c37cf80be 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2082,7 +2082,7 @@ InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) { } bool Layer::hasInput() const { - return mDrawingState.inputInfo.inputChannel != nullptr; + return mDrawingState.inputInfo.token != nullptr; } // --------------------------------------------------------------------------- -- cgit v1.2.3-59-g8ed1b From 740167f1a2b5a141debb0efc952eb4e57152bdd4 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Thu, 11 Oct 2018 19:03:41 -0700 Subject: Rework InputApplicationInfo First we move it inside of InputWindowInfo instead of InputWindowHandle so it is part of the data sent across binder. Second we give it a persistent identity of an IBinder token and use this for comparisons. Bug: 80101428 Bug: 113136004 Bug: 111440400 Test: EndToEndNativeInputTest. Existing tests pass. Change-Id: Id89a40e66887d834020f8e645fd1fb48adb7ee2e --- include/input/InputApplication.h | 11 +++++++++++ include/input/InputWindow.h | 8 ++++++-- libs/gui/tests/EndToEndNativeInputTest.cpp | 7 +++++++ libs/input/InputApplication.cpp | 17 +++++++++++++++++ libs/input/InputWindow.cpp | 5 +++-- services/inputflinger/InputDispatcher.cpp | 21 +++++++++++---------- services/inputflinger/InputDispatcher.h | 2 +- services/inputflinger/InputManager.cpp | 13 +------------ .../inputflinger/tests/InputDispatcher_test.cpp | 7 ++++++- 9 files changed, 63 insertions(+), 28 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h index 9b365b9f0d..71a8f20468 100644 --- a/include/input/InputApplication.h +++ b/include/input/InputApplication.h @@ -19,6 +19,9 @@ #include +#include +#include + #include #include #include @@ -29,8 +32,12 @@ namespace android { * Describes the properties of an application that can receive input. */ struct InputApplicationInfo { + sp token; std::string name; nsecs_t dispatchingTimeout; + + status_t write(Parcel& output) const; + static InputApplicationInfo read(const Parcel& from); }; @@ -54,6 +61,10 @@ public: return mInfo ? mInfo->dispatchingTimeout : defaultValue; } + inline sp getApplicationToken() const { + return mInfo ? mInfo->token : nullptr; + } + /** * Requests that the state of this object be updated to reflect * the most current available information about the application. diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 6164aa6f09..1a46825692 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -138,6 +138,7 @@ struct InputWindowInfo { int32_t ownerUid; int32_t inputFeatures; int32_t displayId; + InputApplicationInfo applicationInfo; void addTouchableRegion(const Rect& region); @@ -168,7 +169,6 @@ struct InputWindowInfo { */ class InputWindowHandle : public RefBase { public: - const sp inputApplicationHandle; inline const InputWindowInfo* getInfo() const { return &mInfo; @@ -176,6 +176,10 @@ public: sp getToken() const; + sp getApplicationToken() { + return mInfo.applicationInfo.token; + } + inline std::string getName() const { return mInfo.token ? mInfo.name : ""; } @@ -202,7 +206,7 @@ public: void releaseChannel(); protected: - explicit InputWindowHandle(const sp& inputApplicationHandle); + explicit InputWindowHandle(); virtual ~InputWindowHandle(); InputWindowInfo mInfo; diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 7b727047d1..2cc0c54708 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -153,6 +153,13 @@ private: mInputInfo.ownerUid = 11111; mInputInfo.inputFeatures = 0; mInputInfo.displayId = 0; + + InputApplicationInfo aInfo; + aInfo.token = new BBinder(); + aInfo.name = "Test app info"; + aInfo.dispatchingTimeout = 100000; + + mInputInfo.applicationInfo = aInfo; } public: sp mSurfaceControl; diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp index a0d1668029..7936f50d54 100644 --- a/libs/input/InputApplication.cpp +++ b/libs/input/InputApplication.cpp @@ -39,4 +39,21 @@ void InputApplicationHandle::releaseInfo() { } } +InputApplicationInfo InputApplicationInfo::read(const Parcel& from) { + InputApplicationInfo ret; + ret.token = from.readStrongBinder(); + ret.name = from.readString8().c_str(); + ret.dispatchingTimeout = from.readInt64(); + + return ret; +} + +status_t InputApplicationInfo::write(Parcel& output) const { + output.writeStrongBinder(token); + output.writeString8(String8(name.c_str())); + output.writeInt64(dispatchingTimeout); + + return OK; +} + } // namespace android diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index 96646dc6f8..b1d9d6af15 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -92,6 +92,7 @@ status_t InputWindowInfo::write(Parcel& output) const { output.writeInt32(ownerUid); output.writeInt32(inputFeatures); output.writeInt32(displayId); + applicationInfo.write(output); output.write(touchableRegion); return OK; @@ -129,6 +130,7 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { ret.ownerUid = from.readInt32(); ret.inputFeatures = from.readInt32(); ret.displayId = from.readInt32(); + ret.applicationInfo = InputApplicationInfo::read(from); from.read(ret.touchableRegion); return ret; @@ -140,8 +142,7 @@ InputWindowInfo::InputWindowInfo(const Parcel& from) { // --- InputWindowHandle --- -InputWindowHandle::InputWindowHandle(const sp& inputApplicationHandle) : - inputApplicationHandle(inputApplicationHandle) { +InputWindowHandle::InputWindowHandle() { } InputWindowHandle::~InputWindowHandle() { diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index e0082a5a95..49aac72e28 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -489,7 +489,7 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY - && mInputTargetWaitApplicationHandle != nullptr) { + && mInputTargetWaitApplicationToken != nullptr) { int32_t displayId = motionEntry->displayId; int32_t x = int32_t(motionEntry->pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_X)); @@ -497,8 +497,8 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { getAxisValue(AMOTION_EVENT_AXIS_Y)); sp touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); if (touchedWindowHandle != nullptr - && touchedWindowHandle->inputApplicationHandle - != mInputTargetWaitApplicationHandle) { + && touchedWindowHandle->getApplicationToken() + != mInputTargetWaitApplicationToken) { // User touched a different application than the one we are waiting on. // Flag the event, and start pruning the input queue. mNextUnblockedEvent = motionEntry; @@ -819,7 +819,8 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, sp focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry)); if (focusedWindowHandle != nullptr) { - commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken()); + commandEntry->inputChannel = + getInputChannelLocked(focusedWindowHandle->getToken()); } commandEntry->keyEntry = entry; entry->refCount += 1; @@ -1010,7 +1011,7 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = LONG_LONG_MAX; mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationHandle.clear(); + mInputTargetWaitApplicationToken.clear(); } } else { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { @@ -1033,13 +1034,13 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = currentTime + timeout; mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationHandle.clear(); + mInputTargetWaitApplicationToken.clear(); if (windowHandle != nullptr) { - mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle; + mInputTargetWaitApplicationToken = windowHandle->getApplicationToken(); } - if (mInputTargetWaitApplicationHandle == nullptr && applicationHandle != nullptr) { - mInputTargetWaitApplicationHandle = applicationHandle; + if (mInputTargetWaitApplicationToken == nullptr && applicationHandle != nullptr) { + mInputTargetWaitApplicationToken = applicationHandle->getApplicationToken(); } } } @@ -1117,7 +1118,7 @@ void InputDispatcher::resetANRTimeoutsLocked() { // Reset input target wait timeout. mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; - mInputTargetWaitApplicationHandle.clear(); + mInputTargetWaitApplicationToken.clear(); } /** diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 38c7b45c59..9ecabdbf08 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -1060,7 +1060,7 @@ private: nsecs_t mInputTargetWaitStartTime; nsecs_t mInputTargetWaitTimeoutTime; bool mInputTargetWaitTimeoutExpired; - sp mInputTargetWaitApplicationHandle; + sp mInputTargetWaitApplicationToken; // Contains the last window which received a hover event. sp mLastHoverWindowHandle; diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index cf3ca42d93..15d80703aa 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -87,20 +87,9 @@ sp InputManager::getDispatcher() { return mDispatcher; } -class BinderApplicationHandle : public InputApplicationHandle { -public: - BinderApplicationHandle() = default; - - bool updateInfo() override { - return true; - } -}; - class BinderWindowHandle : public InputWindowHandle { public: - BinderWindowHandle(const InputWindowInfo& info) : - InputWindowHandle(new BinderApplicationHandle()) { - + BinderWindowHandle(const InputWindowInfo& info) { mInfo = info; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 26adcdd8a9..3afee73b02 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -63,6 +63,9 @@ private: virtual void notifyInputChannelBroken(const sp&) { } + virtual void notifyFocusChanged(const sp&) { + } + virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { *outConfig = mConfig; } @@ -366,11 +369,13 @@ public: FakeWindowHandle(const sp& inputApplicationHandle, const sp& dispatcher, const std::string name, int32_t displayId) : - InputWindowHandle(inputApplicationHandle), FakeInputReceiver(dispatcher, name, displayId), mFocused(false) { mServerChannel->setToken(new BBinder()); mDispatcher->registerInputChannel(mServerChannel, displayId); + + inputApplicationHandle->updateInfo(); + mInfo.applicationInfo = *inputApplicationHandle->getInfo(); } virtual bool updateInfo() { -- cgit v1.2.3-59-g8ed1b From 5cb25783960d19e2b529b134287dd33e2099d466 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 14 Nov 2018 14:01:42 -0800 Subject: SurfaceFlinger Input: Shrink frame by surfaceInsets. Probably best explained by the comment in InputWindow.h. We can't use touchable region because we need to shift the coordinate space. As a follow-up I'm going to look in to shifting the coordinate space on the client but it was very non obvious where to do so. Test: Manual Bug: 80101428 Bug: 113136004 Bug: 111440400 Change-Id: Ibbaffa89a80f3a047c716265251f547631bdf802 --- include/input/InputWindow.h | 21 ++++++++++++++++++++- libs/input/InputWindow.cpp | 2 ++ libs/input/tests/InputWindow_test.cpp | 2 ++ services/surfaceflinger/Layer.cpp | 10 +++++----- 4 files changed, 29 insertions(+), 6 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 1a46825692..df401f0d93 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -116,17 +116,36 @@ struct InputWindowInfo { INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002, INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004, }; - + + /* These values are filled in by the WM and passed through SurfaceFlinger + * unless specified otherwise. + */ sp token; std::string name; int32_t layoutParamsFlags; int32_t layoutParamsType; nsecs_t dispatchingTimeout; + + /* These values are filled in by SurfaceFlinger. */ int32_t frameLeft; int32_t frameTop; int32_t frameRight; int32_t frameBottom; + + /* + * SurfaceFlinger consumes this value to shrink the computed frame. This is + * different from shrinking the touchable region in that it DOES shift the coordinate + * space where-as the touchable region does not and is more like "cropping". This + * is used for window shadows. + */ + int32_t surfaceInset = 0; + float scaleFactor; + + /* + * This is filled in by the WM relative to the frame and then translated + * to absolute coordinates by SurfaceFlinger once the frame is computed. + */ Region touchableRegion; bool visible; bool canReceiveKeys; diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index b1d9d6af15..e6bb255c74 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -81,6 +81,7 @@ status_t InputWindowInfo::write(Parcel& output) const { output.writeInt32(frameTop); output.writeInt32(frameRight); output.writeInt32(frameBottom); + output.writeInt32(surfaceInset); output.writeFloat(scaleFactor); output.writeBool(visible); output.writeBool(canReceiveKeys); @@ -119,6 +120,7 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { ret.frameTop = from.readInt32(); ret.frameRight = from.readInt32(); ret.frameBottom = from.readInt32(); + ret.surfaceInset = from.readInt32(); ret.scaleFactor = from.readFloat(); ret.visible = from.readBool(); ret.canReceiveKeys = from.readBool(); diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp index ea98f8a302..cc6962f65d 100644 --- a/libs/input/tests/InputWindow_test.cpp +++ b/libs/input/tests/InputWindow_test.cpp @@ -47,6 +47,7 @@ TEST(InputWindowInfo, Parcelling) { i.frameTop = 34; i.frameRight = 16; i.frameBottom = 19; + i.surfaceInset = 17; i.scaleFactor = 0.3; i.visible = false; i.canReceiveKeys = false; @@ -73,6 +74,7 @@ TEST(InputWindowInfo, Parcelling) { ASSERT_EQ(i.frameTop, i2.frameTop); ASSERT_EQ(i.frameRight, i2.frameRight); ASSERT_EQ(i.frameBottom, i2.frameBottom); + ASSERT_EQ(i.surfaceInset, i2.surfaceInset); ASSERT_EQ(i.scaleFactor, i2.scaleFactor); ASSERT_EQ(i.visible, i2.visible); ASSERT_EQ(i.canReceiveKeys, i2.canReceiveKeys); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3c37cf80be..bfae03dd91 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2069,12 +2069,12 @@ bool Layer::isRemovedFromCurrentState() const { InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) { InputWindowInfo info = mDrawingState.inputInfo; - info.frameLeft = screenBounds.left; - info.inputInfo.frameTop = screenBounds.top; - info.inputInfo.frameRight = screenBounds.right; - info.inputInfo.frameBottom = screenBounds.bottom; + info.frameLeft = screenBounds.left + info.surfaceInset; + info.frameTop = screenBounds.top + info.surfaceInset; + info.frameRight = screenBounds.right - info.surfaceInset; + info.frameBottom = screenBounds.bottom - info.surfaceInset; - info.touchableRegion = mDrawingState.inputInfo.touchableRegion.translate( + info.touchableRegion = info.touchableRegion.translate( screenBounds.left, screenBounds.top); info.visible = isVisible(); -- cgit v1.2.3-59-g8ed1b From e07e103103d575789ad0a9d5a5212a000ad1f277 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 26 Nov 2018 12:55:53 -0800 Subject: SurfaceFlinger Input: Correct screen magnification. We need to pass the computed scaling factors through SurfaceFlinger as well as appropriately scaling the touchable region. We also need to be careful as to which axes we scale. In the past screen magnification has not lead to scaling of the TOUCH_MAJOR/MINOR axes, whereas whole-screen display compatibility scaling has. We preserve this behavior by differentiating between the global scale and a scale on any particular window. The window scale works like the global scale used to and the global scale is only used for additional scaling of the MAJOR/MINOR axes. Bug: 80101428 Bug: 113136004 Bug: 111440400 Change-Id: I97d809826f86b452f28443cb1046e8bfef1bbf9d --- include/input/Input.h | 9 ++++- include/input/InputWindow.h | 8 +++- libs/gui/tests/EndToEndNativeInputTest.cpp | 2 +- libs/input/Input.cpp | 35 ++++++++++------ libs/input/InputWindow.cpp | 8 +++- libs/input/tests/InputWindow_test.cpp | 8 +++- libs/ui/Region.cpp | 14 +++++++ libs/ui/Transform.cpp | 8 ++++ libs/ui/include/ui/Region.h | 2 + libs/ui/include/ui/Transform.h | 2 + services/inputflinger/InputDispatcher.cpp | 46 ++++++++++++++-------- services/inputflinger/InputDispatcher.h | 11 ++++-- .../inputflinger/tests/InputDispatcher_test.cpp | 2 +- services/surfaceflinger/Layer.cpp | 6 +++ 14 files changed, 119 insertions(+), 42 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/include/input/Input.h b/include/input/Input.h index cc45aefe9b..ee22bc6371 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -244,7 +244,12 @@ struct PointerCoords { float getAxisValue(int32_t axis) const; status_t setAxisValue(int32_t axis, float value); - void scale(float scale); + void scale(float globalScale); + + // Scale the pointer coordinates according to a global scale and a + // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR + // axes, however the window scaling will not. + void scale(float globalScale, float windowXScale, float windowYScale); void applyOffset(float xOffset, float yOffset); inline float getX() const { @@ -595,7 +600,7 @@ public: void offsetLocation(float xOffset, float yOffset); - void scale(float scaleFactor); + void scale(float globalScaleFactor); // Apply 3x3 perspective matrix transformation. // Matrix is in row-major form and compatible with SkMatrix. diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index df401f0d93..8dd95cfb9a 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -140,7 +140,13 @@ struct InputWindowInfo { */ int32_t surfaceInset = 0; - float scaleFactor; + // A global scaling factor for all windows. Unlike windowScaleX/Y this results + // in scaling of the TOUCH_MAJOR/TOUCH_MINOR axis. + float globalScaleFactor; + + // Scaling factors applied to individual windows. + float windowXScale = 1.0f; + float windowYScale = 1.0f; /* * This is filled in by the WM relative to the frame and then translated diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 2cc0c54708..2871302927 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -140,7 +140,7 @@ private: mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL; mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION; mInputInfo.dispatchingTimeout = 100000; - mInputInfo.scaleFactor = 1.0; + mInputInfo.globalScaleFactor = 1.0; mInputInfo.canReceiveKeys = true; mInputInfo.hasFocus = true; mInputInfo.hasWallpaper = false; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 8a15e2f40f..a558970b58 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -131,15 +131,24 @@ static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) } } -void PointerCoords::scale(float scaleFactor) { +void PointerCoords::scale(float globalScaleFactor, float windowXScale, float windowYScale) { // No need to scale pressure or size since they are normalized. // No need to scale orientation since it is meaningless to do so. - scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor); + + // If there is a global scale factor, it is included in the windowX/YScale + // so we don't need to apply it twice to the X/Y axes. + // However we don't want to apply any windowXYScale not included in the global scale + // to the TOUCH_MAJOR/MINOR coordinates. + scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, windowXScale); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, windowYScale); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, globalScaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, globalScaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, globalScaleFactor); + scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor); +} + +void PointerCoords::scale(float globalScaleFactor) { + scale(globalScaleFactor, globalScaleFactor, globalScaleFactor); } void PointerCoords::applyOffset(float xOffset, float yOffset) { @@ -345,15 +354,15 @@ void MotionEvent::offsetLocation(float xOffset, float yOffset) { mYOffset += yOffset; } -void MotionEvent::scale(float scaleFactor) { - mXOffset *= scaleFactor; - mYOffset *= scaleFactor; - mXPrecision *= scaleFactor; - mYPrecision *= scaleFactor; +void MotionEvent::scale(float globalScaleFactor) { + mXOffset *= globalScaleFactor; + mYOffset *= globalScaleFactor; + mXPrecision *= globalScaleFactor; + mYPrecision *= globalScaleFactor; size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { - mSamplePointerCoords.editItemAt(i).scale(scaleFactor); + mSamplePointerCoords.editItemAt(i).scale(globalScaleFactor); } } diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index e6bb255c74..556a005580 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -82,7 +82,9 @@ status_t InputWindowInfo::write(Parcel& output) const { output.writeInt32(frameRight); output.writeInt32(frameBottom); output.writeInt32(surfaceInset); - output.writeFloat(scaleFactor); + output.writeFloat(globalScaleFactor); + output.writeFloat(windowXScale); + output.writeFloat(windowYScale); output.writeBool(visible); output.writeBool(canReceiveKeys); output.writeBool(hasFocus); @@ -121,7 +123,9 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { ret.frameRight = from.readInt32(); ret.frameBottom = from.readInt32(); ret.surfaceInset = from.readInt32(); - ret.scaleFactor = from.readFloat(); + ret.globalScaleFactor = from.readFloat(); + ret.windowXScale = from.readFloat(); + ret.windowYScale = from.readFloat(); ret.visible = from.readBool(); ret.canReceiveKeys = from.readBool(); ret.hasFocus = from.readBool(); diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp index cc6962f65d..5e5893fe4c 100644 --- a/libs/input/tests/InputWindow_test.cpp +++ b/libs/input/tests/InputWindow_test.cpp @@ -48,7 +48,9 @@ TEST(InputWindowInfo, Parcelling) { i.frameRight = 16; i.frameBottom = 19; i.surfaceInset = 17; - i.scaleFactor = 0.3; + i.globalScaleFactor = 0.3; + i.windowXScale = 0.4; + i.windowYScale = 0.5; i.visible = false; i.canReceiveKeys = false; i.hasFocus = false; @@ -75,7 +77,9 @@ TEST(InputWindowInfo, Parcelling) { ASSERT_EQ(i.frameRight, i2.frameRight); ASSERT_EQ(i.frameBottom, i2.frameBottom); ASSERT_EQ(i.surfaceInset, i2.surfaceInset); - ASSERT_EQ(i.scaleFactor, i2.scaleFactor); + ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor); + ASSERT_EQ(i.windowXScale, i2.windowXScale); + ASSERT_EQ(i.windowYScale, i2.windowYScale); ASSERT_EQ(i.visible, i2.visible); ASSERT_EQ(i.canReceiveKeys, i2.canReceiveKeys); ASSERT_EQ(i.hasFocus, i2.hasFocus); diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index fe4ae6c414..815093174c 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -325,6 +325,20 @@ Region& Region::translateSelf(int x, int y) { return *this; } +Region& Region::scaleSelf(int sx, int sy) { + size_t count = mStorage.size(); + Rect* rects = mStorage.editArray(); + while (count) { + rects->left *= sx; + rects->right *= sx; + rects->top *= sy; + rects->bottom *= sy; + rects++; + count--; + } + return *this; +} + // ---------------------------------------------------------------------------- const Region Region::merge(const Rect& rhs) const { diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp index 8e949ec880..25128effaf 100644 --- a/libs/ui/Transform.cpp +++ b/libs/ui/Transform.cpp @@ -95,6 +95,14 @@ float Transform::ty() const { return mMatrix[2][1]; } +float Transform::sx() const { + return mMatrix[0][0]; +} + +float Transform::sy() const { + return mMatrix[1][1]; +} + void Transform::reset() { mType = IDENTITY; for(size_t i = 0; i < 3; i++) { diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h index 68b60fc2e2..c5e31c56f1 100644 --- a/libs/ui/include/ui/Region.h +++ b/libs/ui/include/ui/Region.h @@ -89,11 +89,13 @@ public: // these translate rhs first Region& translateSelf(int dx, int dy); + Region& scaleSelf(int sx, int sy); Region& orSelf(const Region& rhs, int dx, int dy); Region& xorSelf(const Region& rhs, int dx, int dy); Region& andSelf(const Region& rhs, int dx, int dy); Region& subtractSelf(const Region& rhs, int dx, int dy); + // these translate rhs first const Region translate(int dx, int dy) const WARN_UNUSED; const Region merge(const Region& rhs, int dx, int dy) const WARN_UNUSED; diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h index 42dca75f6b..900a5c46eb 100644 --- a/libs/ui/include/ui/Transform.h +++ b/libs/ui/include/ui/Transform.h @@ -65,6 +65,8 @@ public: const vec3& operator [] (size_t i) const; // returns column i float tx() const; float ty() const; + float sx() const; + float sy() const; // modify the transform void reset(); diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 93a8ac0fff..bea4f911d9 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -1671,7 +1671,9 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowH target.flags = targetFlags; target.xOffset = - windowInfo->frameLeft; target.yOffset = - windowInfo->frameTop; - target.scaleFactor = windowInfo->scaleFactor; + target.globalScaleFactor = windowInfo->globalScaleFactor; + target.windowXScale = windowInfo->windowXScale; + target.windowYScale = windowInfo->windowYScale; target.pointerIds = pointerIds; } @@ -1692,7 +1694,7 @@ void InputDispatcher::addMonitoringTargetsLocked(Vector& inputTarge target.xOffset = 0; target.yOffset = 0; target.pointerIds.clear(); - target.scaleFactor = 1.0f; + target.globalScaleFactor = 1.0f; } } else { // If there is no monitor channel registered or all monitor channel unregistered, @@ -1912,11 +1914,13 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " - "xOffset=%f, yOffset=%f, scaleFactor=%f, " - "pointerIds=0x%x", + "xOffset=%f, yOffset=%f, globalScaleFactor=%f, " + "windowScaleFactor=(%f, %f), pointerIds=0x%x", connection->getInputChannelName().c_str(), inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset, - inputTarget->scaleFactor, inputTarget->pointerIds.value); + inputTarget->globalScaleFactor, + inputTarget->windowXScale, inputTarget->windowYScale, + inputTarget->pointerIds.value); #endif // Skip this event if the connection status is not normal. @@ -1993,7 +1997,8 @@ void InputDispatcher::enqueueDispatchEntryLocked( // Enqueue a new dispatch entry onto the outbound queue for this connection. DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, - inputTarget->scaleFactor); + inputTarget->globalScaleFactor, inputTarget->windowXScale, + inputTarget->windowYScale); // Apply target flags and update the connection's input state. switch (eventEntry->type) { @@ -2109,13 +2114,15 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, float xOffset, yOffset; if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { - float scaleFactor = dispatchEntry->scaleFactor; - xOffset = dispatchEntry->xOffset * scaleFactor; - yOffset = dispatchEntry->yOffset * scaleFactor; - if (scaleFactor != 1.0f) { + float globalScaleFactor = dispatchEntry->globalScaleFactor; + float wxs = dispatchEntry->windowXScale; + float wys = dispatchEntry->windowYScale; + xOffset = dispatchEntry->xOffset * wxs; + yOffset = dispatchEntry->yOffset * wys; + if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) { for (uint32_t i = 0; i < motionEntry->pointerCount; i++) { scaledCoords[i] = motionEntry->pointerCoords[i]; - scaledCoords[i].scale(scaleFactor); + scaledCoords[i].scale(globalScaleFactor, wxs, wys); } usingCoords = scaledCoords; } @@ -2373,11 +2380,13 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( const InputWindowInfo* windowInfo = windowHandle->getInfo(); target.xOffset = -windowInfo->frameLeft; target.yOffset = -windowInfo->frameTop; - target.scaleFactor = windowInfo->scaleFactor; + target.globalScaleFactor = windowInfo->globalScaleFactor; + target.windowXScale = windowInfo->windowXScale; + target.windowYScale = windowInfo->windowYScale; } else { target.xOffset = 0; target.yOffset = 0; - target.scaleFactor = 1.0f; + target.globalScaleFactor = 1.0f; } target.inputChannel = connection->inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; @@ -3509,7 +3518,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, " "paused=%s, hasFocus=%s, hasWallpaper=%s, " "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], scale=%f, " + "frame=[%d,%d][%d,%d], globalScale=%f, windowScale=%f,%f" "touchableRegion=", i, windowInfo->name.c_str(), windowInfo->displayId, toString(windowInfo->paused), @@ -3521,7 +3530,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { windowInfo->layer, windowInfo->frameLeft, windowInfo->frameTop, windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->scaleFactor); + windowInfo->globalScaleFactor, + windowInfo->windowXScale, windowInfo->windowYScale); dumpRegion(dump, windowInfo->touchableRegion); dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", @@ -4383,10 +4393,12 @@ void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const { volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic; InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) : + int32_t targetFlags, float xOffset, float yOffset, float globalScaleFactor, + float windowXScale, float windowYScale) : seq(nextSeq()), eventEntry(eventEntry), targetFlags(targetFlags), - xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor), + xOffset(xOffset), yOffset(yOffset), globalScaleFactor(globalScaleFactor), + windowXScale(windowXScale), windowYScale(windowYScale), deliveryTime(0), resolvedAction(0), resolvedFlags(0) { eventEntry->refCount += 1; } diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 11df5d91d9..73bcc25848 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -160,7 +160,9 @@ struct InputTarget { // Scaling factor to apply to MotionEvent as it is delivered. // (ignored for KeyEvents) - float scaleFactor; + float globalScaleFactor; + float windowXScale = 1.0f; + float windowYScale = 1.0f; // The subset of pointer ids to include in motion events dispatched to this input target // if FLAG_SPLIT is set. @@ -563,7 +565,9 @@ private: int32_t targetFlags; float xOffset; float yOffset; - float scaleFactor; + float globalScaleFactor; + float windowXScale = 1.0f; + float windowYScale = 1.0f; nsecs_t deliveryTime; // time when the event was actually delivered // Set to the resolved action and flags when the event is enqueued. @@ -571,7 +575,8 @@ private: int32_t resolvedFlags; DispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor); + int32_t targetFlags, float xOffset, float yOffset, + float globalScaleFactor, float windowXScale, float windowYScale); ~DispatchEntry(); inline bool hasForegroundTarget() const { diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 3afee73b02..26f01b7eb5 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -388,7 +388,7 @@ public: mInfo.frameTop = 0; mInfo.frameRight = WIDTH; mInfo.frameBottom = HEIGHT; - mInfo.scaleFactor = 1.0; + mInfo.globalScaleFactor = 1.0; mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT)); mInfo.visible = true; mInfo.canReceiveKeys = true; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index bfae03dd91..6ac09016bb 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2074,6 +2074,12 @@ InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) { info.frameRight = screenBounds.right - info.surfaceInset; info.frameBottom = screenBounds.bottom - info.surfaceInset; + ui::Transform t = getTransform(); + info.windowXScale *= 1.0f / t.sx(); + info.windowYScale *= 1.0f / t.sy(); + + info.touchableRegion.scaleSelf(t.sx(), t.sy()); + info.touchableRegion = info.touchableRegion.translate( screenBounds.left, screenBounds.top); -- cgit v1.2.3-59-g8ed1b From bd0fbcd1f37f4e7e2e505cf5e5ede0fe52a3767c Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Fri, 30 Nov 2018 12:45:03 -0800 Subject: Keep instance of BinderInputWindow for the same token. Some code in InputDispatcher uses pointer value comparison to track if a BinderInputWindow is the same. Therefore just keep the initial instance and reuse that for every update. This is better than changing all pointer comparisons to token comparisons because it would be hard to make sure every comparison is changed. Later we could simply drop InputWindowHandle and use InputWindowInfo value instead. It would also be better if it could implement move constructor so that we can use move semantics. Bug: 120289807 Bug: 120463595 Bug: 120481017 Test: Verified that input focus stops constantly changing by inpecting logcat after enabling DEBUG_FOCUS in InputDispatcher.cpp. Freeform drag-resize works with a workaround to another race condition. Change-Id: I34bbf8c076373ef23494f858536c5188eff95abd --- include/input/InputWindow.h | 5 ++++ libs/input/InputWindow.cpp | 4 ++++ services/inputflinger/InputDispatcher.cpp | 38 ++++++++++++++++++++++++------- 3 files changed, 39 insertions(+), 8 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 8dd95cfb9a..2b8cc57c05 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -224,6 +224,11 @@ public: */ virtual bool updateInfo() = 0; + /** + * Updates from another input window handle. + */ + void updateFrom(const sp handle); + /** * Releases the channel used by the associated information when it is * no longer needed. diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index 556a005580..aa1371fdc9 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -162,4 +162,8 @@ sp InputWindowHandle::getToken() const { return mInfo.token; } +void InputWindowHandle::updateFrom(sp handle) { + mInfo = handle->mInfo; +} + } // namespace android diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 12d91bbd68..a498fa154c 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -3077,22 +3077,44 @@ void InputDispatcher::setInputWindows(const Vector>& input // Remove all handles on a display if there are no windows left. mWindowHandlesByDisplay.erase(displayId); } else { - size_t numWindows = inputWindowHandles.size(); + // Since we compare the pointer of input window handles across window updates, we need + // to make sure the handle object for the same window stays unchanged across updates. + const Vector>& oldHandles = mWindowHandlesByDisplay[displayId]; + std::unordered_map, sp, IBinderHash> oldHandlesByTokens; + for (size_t i = 0; i < oldHandles.size(); i++) { + const sp& handle = oldHandles.itemAt(i); + oldHandlesByTokens[handle->getToken()] = handle; + } + + const size_t numWindows = inputWindowHandles.size(); + Vector> newHandles; for (size_t i = 0; i < numWindows; i++) { - const sp& windowHandle = inputWindowHandles.itemAt(i); - if (!windowHandle->updateInfo() || getInputChannelLocked(windowHandle->getToken()) == nullptr) { + const sp& handle = inputWindowHandles.itemAt(i); + if (!handle->updateInfo() || getInputChannelLocked(handle->getToken()) == nullptr) { ALOGE("Window handle %s has no registered input channel", - windowHandle->getName().c_str()); + handle->getName().c_str()); continue; } - if (windowHandle->getInfo()->displayId != displayId) { + if (handle->getInfo()->displayId != displayId) { ALOGE("Window %s updated by wrong display %d, should belong to display %d", - windowHandle->getName().c_str(), displayId, - windowHandle->getInfo()->displayId); + handle->getName().c_str(), displayId, + handle->getInfo()->displayId); continue; } + if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) { + const sp oldHandle = + oldHandlesByTokens.at(handle->getToken()); + oldHandle->updateFrom(handle); + newHandles.push_back(oldHandle); + } else { + newHandles.push_back(handle); + } + } + + for (size_t i = 0; i < newHandles.size(); i++) { + const sp& windowHandle = newHandles.itemAt(i); if (windowHandle->getInfo()->hasFocus && windowHandle->getInfo()->visible) { newFocusedWindowHandle = windowHandle; } @@ -3102,7 +3124,7 @@ void InputDispatcher::setInputWindows(const Vector>& input } // Insert or replace - mWindowHandlesByDisplay[displayId] = inputWindowHandles; + mWindowHandlesByDisplay[displayId] = newHandles; } if (!foundHoveredWindow) { -- cgit v1.2.3-59-g8ed1b From 85b8c5edd4c3ffd9790e2d69a9e8bcd9df2fa42c Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Thu, 17 Jan 2019 18:34:54 +0800 Subject: Introduce new portal window which transports touch to another display It enables the user to directly touch on a window of a display embedded on another one. The embedded displays can be nested. The monitoring channels of the embedded display can also receive touch events. Bug: 120675821 Test: Manual test with ActivityViewTest Test: atest -a inputflinger_tests Test: atest CtsActivityManagerDeviceTestCases:ActivityViewTest Change-Id: I773c7efb1b048080020aadd45156261a10095fcb --- include/input/InputWindow.h | 1 + libs/input/InputWindow.cpp | 2 + libs/input/tests/InputWindow_test.cpp | 2 + services/inputflinger/InputDispatcher.cpp | 99 +++++++++++++++++++------------ services/inputflinger/InputDispatcher.h | 12 +++- services/surfaceflinger/Layer.cpp | 9 ++- 6 files changed, 85 insertions(+), 40 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 2b8cc57c05..a065a4ce28 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -163,6 +163,7 @@ struct InputWindowInfo { int32_t ownerUid; int32_t inputFeatures; int32_t displayId; + int32_t portalToDisplayId = ADISPLAY_ID_NONE; InputApplicationInfo applicationInfo; void addTouchableRegion(const Rect& region); diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index aa1371fdc9..5c5613df82 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -95,6 +95,7 @@ status_t InputWindowInfo::write(Parcel& output) const { output.writeInt32(ownerUid); output.writeInt32(inputFeatures); output.writeInt32(displayId); + output.writeInt32(portalToDisplayId); applicationInfo.write(output); output.write(touchableRegion); @@ -136,6 +137,7 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { ret.ownerUid = from.readInt32(); ret.inputFeatures = from.readInt32(); ret.displayId = from.readInt32(); + ret.portalToDisplayId = from.readInt32(); ret.applicationInfo = InputApplicationInfo::read(from); from.read(ret.touchableRegion); diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp index 5e5893fe4c..09dd72b13b 100644 --- a/libs/input/tests/InputWindow_test.cpp +++ b/libs/input/tests/InputWindow_test.cpp @@ -61,6 +61,7 @@ TEST(InputWindowInfo, Parcelling) { i.ownerUid = 24; i.inputFeatures = 29; i.displayId = 34; + i.portalToDisplayId = 2; Parcel p; i.write(p); @@ -90,6 +91,7 @@ TEST(InputWindowInfo, Parcelling) { ASSERT_EQ(i.ownerUid, i2.ownerUid); ASSERT_EQ(i.inputFeatures, i2.inputFeatures); ASSERT_EQ(i.displayId, i2.displayId); + ASSERT_EQ(i.portalToDisplayId, i2.portalToDisplayId); } } // namespace test diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 9d92435323..37c65f517e 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -525,7 +525,7 @@ void InputDispatcher::addRecentEventLocked(EventEntry* entry) { } sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, - int32_t x, int32_t y) { + int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) { // Traverse windows from front to back to find touched window. const Vector> windowHandles = getWindowHandlesLocked(displayId); size_t numWindows = windowHandles.size(); @@ -540,10 +540,25 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t display bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { + int32_t portalToDisplayId = windowInfo->portalToDisplayId; + if (portalToDisplayId != ADISPLAY_ID_NONE + && portalToDisplayId != displayId) { + if (addPortalWindows) { + // For the monitoring channels of the display. + mTempTouchState.addPortalWindow(windowHandle); + } + return findTouchedWindowAtLocked( + portalToDisplayId, x, y, addOutsideTargets, addPortalWindows); + } // Found window. return windowHandle; } } + + if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { + mTempTouchState.addOrUpdateWindow( + windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0)); + } } } } @@ -930,6 +945,22 @@ bool InputDispatcher::dispatchMotionLocked( // Add monitor channels from event's or focused display. addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry)); + if (isPointerEvent) { + ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId); + if (stateIndex >= 0) { + const TouchState& state = mTouchStatesByDisplay.valueAt(stateIndex); + if (!state.portalWindows.isEmpty()) { + // The event has gone through these portal windows, so we add monitoring targets of + // the corresponding displays as well. + for (size_t i = 0; i < state.portalWindows.size(); i++) { + const InputWindowInfo* windowInfo = state.portalWindows.itemAt(i)->getInfo(); + addMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId, + -windowInfo->frameLeft, -windowInfo->frameTop); + } + } + } + } + // Dispatch the motion. if (conflictingPointerActions) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, @@ -1297,37 +1328,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp newTouchedWindowHandle; - bool isTouchModal = false; - - // Traverse windows from front to back to find touched window and outside targets. - const Vector> windowHandles = getWindowHandlesLocked(displayId); - size_t numWindows = windowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp windowHandle = windowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - if (windowInfo->displayId != displayId) { - continue; // wrong display - } - - int32_t flags = windowInfo->layoutParamsFlags; - if (windowInfo->visible) { - if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE - | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { - newTouchedWindowHandle = windowHandle; - break; // found touched window, exit window loop - } - } - - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { - mTempTouchState.addOrUpdateWindow( - windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0)); - } - } - } + sp newTouchedWindowHandle = findTouchedWindowAtLocked( + displayId, x, y, maskedAction == AMOTION_EVENT_ACTION_DOWN, true); // Figure out whether splitting will be allowed for this window. if (newTouchedWindowHandle != nullptr @@ -1689,7 +1691,7 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowH } void InputDispatcher::addMonitoringTargetsLocked(Vector& inputTargets, - int32_t displayId) { + int32_t displayId, float xOffset, float yOffset) { std::unordered_map>>::const_iterator it = mMonitoringChannelsByDisplay.find(displayId); @@ -1702,8 +1704,8 @@ void InputDispatcher::addMonitoringTargetsLocked(Vector& inputTarge InputTarget& target = inputTargets.editTop(); target.inputChannel = monitoringChannels[i]; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - target.xOffset = 0; - target.yOffset = 0; + target.xOffset = xOffset; + target.yOffset = yOffset; target.pointerIds.clear(); target.globalScaleFactor = 1.0f; } @@ -3107,7 +3109,8 @@ void InputDispatcher::setInputWindows(const Vector>& input Vector> newHandles; for (size_t i = 0; i < numWindows; i++) { const sp& handle = inputWindowHandles.itemAt(i); - if (!handle->updateInfo() || getInputChannelLocked(handle->getToken()) == nullptr) { + if (!handle->updateInfo() || (getInputChannelLocked(handle->getToken()) == nullptr + && handle->getInfo()->portalToDisplayId == ADISPLAY_ID_NONE)) { ALOGE("Window handle %s has no registered input channel", handle->getName().c_str()); continue; @@ -3542,6 +3545,14 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } else { dump += INDENT3 "Windows: \n"; } + if (!state.portalWindows.isEmpty()) { + dump += INDENT3 "Portal windows:\n"; + for (size_t i = 0; i < state.portalWindows.size(); i++) { + const sp portalWindowHandle = state.portalWindows.itemAt(i); + dump += StringPrintf(INDENT4 "%zu: name='%s'\n", + i, portalWindowHandle->getName().c_str()); + } + } } } else { dump += INDENT "TouchStates: \n"; @@ -3558,11 +3569,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, " - "paused=%s, hasFocus=%s, hasWallpaper=%s, " + "portalToDisplayId=%d, paused=%s, hasFocus=%s, hasWallpaper=%s, " "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " "frame=[%d,%d][%d,%d], globalScale=%f, windowScale=(%f,%f), " "touchableRegion=", i, windowInfo->name.c_str(), windowInfo->displayId, + windowInfo->portalToDisplayId, toString(windowInfo->paused), toString(windowInfo->hasFocus), toString(windowInfo->hasWallpaper), @@ -4911,6 +4923,7 @@ void InputDispatcher::TouchState::reset() { source = 0; displayId = ADISPLAY_ID_NONE; windows.clear(); + portalWindows.clear(); } void InputDispatcher::TouchState::copyFrom(const TouchState& other) { @@ -4920,6 +4933,7 @@ void InputDispatcher::TouchState::copyFrom(const TouchState& other) { source = other.source; displayId = other.displayId; windows = other.windows; + portalWindows = other.portalWindows; } void InputDispatcher::TouchState::addOrUpdateWindow(const sp& windowHandle, @@ -4948,6 +4962,17 @@ void InputDispatcher::TouchState::addOrUpdateWindow(const sp& touchedWindow.pointerIds = pointerIds; } +void InputDispatcher::TouchState::addPortalWindow(const sp& windowHandle) { + size_t numWindows = portalWindows.size(); + for (size_t i = 0; i < numWindows; i++) { + sp portalWindowHandle = portalWindows.itemAt(i); + if (portalWindowHandle == windowHandle) { + return; + } + } + portalWindows.push_back(windowHandle); +} + void InputDispatcher::TouchState::removeWindow(const sp& windowHandle) { for (size_t i = 0; i < windows.size(); i++) { if (windows.itemAt(i).windowHandle == windowHandle) { diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 327dbbd9b1..2d8df5ce5d 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -921,7 +921,8 @@ private: // to transfer focus to a new application. EventEntry* mNextUnblockedEvent; - sp findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y); + sp findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, + bool addOutsideTargets = false, bool addPortalWindows = false); // All registered connections mapped by channel file descriptor. KeyedVector > mConnectionsByFd; @@ -1016,12 +1017,18 @@ private: int32_t displayId; // id to the display that currently has a touch, others are rejected Vector windows; + // This collects the portal windows that the touch has gone through. Each portal window + // targets a display (embedded display for most cases). With this info, we can add the + // monitoring channels of the displays touched. + Vector> portalWindows; + TouchState(); ~TouchState(); void reset(); void copyFrom(const TouchState& other); void addOrUpdateWindow(const sp& windowHandle, int32_t targetFlags, BitSet32 pointerIds); + void addPortalWindow(const sp& windowHandle); void removeWindow(const sp& windowHandle); void removeWindowByToken(const sp& token); void filterNonAsIsTouchWindows(); @@ -1096,7 +1103,8 @@ private: void addWindowTargetLocked(const sp& windowHandle, int32_t targetFlags, BitSet32 pointerIds, Vector& inputTargets); - void addMonitoringTargetsLocked(Vector& inputTargets, int32_t displayId); + void addMonitoringTargetsLocked(Vector& inputTargets, int32_t displayId, + float xOffset = 0, float yOffset = 0); void pokeUserActivityLocked(const EventEntry* eventEntry); bool checkInjectionPermission(const sp& windowHandle, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index aa9bc15f21..6faba524bc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2138,6 +2138,10 @@ bool Layer::isRemovedFromCurrentState() const { InputWindowInfo Layer::fillInputInfo() { InputWindowInfo info = mDrawingState.inputInfo; + if (info.displayId == ADISPLAY_ID_NONE) { + info.displayId = mDrawingState.layerStack; + } + ui::Transform t = getTransform(); const float xScale = t.sx(); const float yScale = t.sy(); @@ -2148,7 +2152,10 @@ InputWindowInfo Layer::fillInputInfo() { } // Transform layer size to screen space and inset it by surface insets. - Rect layerBounds = getBufferSize(getDrawingState()); + // If this is a portal window, set the touchableRegion to the layerBounds. + Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE + ? getBufferSize(getDrawingState()) + : info.touchableRegion.getBounds(); if (!layerBounds.isValid()) { layerBounds = getCroppedBufferSize(getDrawingState()); } -- cgit v1.2.3-59-g8ed1b From 6fabeece7fd6d858699af99cb118e63b8a81147b Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 12 Mar 2019 13:42:49 -0700 Subject: Input: Override touchable region bounds with surface bounds 2/2 Take advantage of the surface flinger layer hierarchy to set touchable region. - Let a client set a surface touchable region to its own bounds. - Let a client set a surface touchable region to another surface bounds. - Let a client bound its touchable region to a surface. Test: go/wm-smoke Test: existing tests Change-Id: I447c93353d067a296007ba8f8341d2420b941d71 --- include/input/InputWindow.h | 4 +++- libs/input/InputWindow.cpp | 5 ++++- libs/input/tests/InputWindow_test.cpp | 5 +++++ services/surfaceflinger/Layer.cpp | 28 ++++++++++++++++++++++++++++ services/surfaceflinger/Layer.h | 1 + 5 files changed, 41 insertions(+), 2 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index a065a4ce28..916af699e0 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -116,7 +116,7 @@ struct InputWindowInfo { INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002, INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004, }; - + /* These values are filled in by the WM and passed through SurfaceFlinger * unless specified otherwise. */ @@ -165,6 +165,8 @@ struct InputWindowInfo { int32_t displayId; int32_t portalToDisplayId = ADISPLAY_ID_NONE; InputApplicationInfo applicationInfo; + bool replaceTouchableRegionWithCrop; + wp touchableRegionCropHandle; void addTouchableRegion(const Rect& region); diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index 5c5613df82..5a60347ed3 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -98,7 +98,8 @@ status_t InputWindowInfo::write(Parcel& output) const { output.writeInt32(portalToDisplayId); applicationInfo.write(output); output.write(touchableRegion); - + output.writeBool(replaceTouchableRegionWithCrop); + output.writeWeakBinder(touchableRegionCropHandle); return OK; } @@ -140,6 +141,8 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { ret.portalToDisplayId = from.readInt32(); ret.applicationInfo = InputApplicationInfo::read(from); from.read(ret.touchableRegion); + ret.replaceTouchableRegionWithCrop = from.readBool(); + ret.touchableRegionCropHandle = from.readWeakBinder(); return ret; } diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp index 09dd72b13b..6db18abacf 100644 --- a/libs/input/tests/InputWindow_test.cpp +++ b/libs/input/tests/InputWindow_test.cpp @@ -37,6 +37,7 @@ TEST(InputWindowInfo, ParcellingWithoutToken) { } TEST(InputWindowInfo, Parcelling) { + sp touchableRegionCropHandle = new BBinder(); InputWindowInfo i; i.token = new BBinder(); i.name = "Foobar"; @@ -62,6 +63,8 @@ TEST(InputWindowInfo, Parcelling) { i.inputFeatures = 29; i.displayId = 34; i.portalToDisplayId = 2; + i.replaceTouchableRegionWithCrop = true; + i.touchableRegionCropHandle = touchableRegionCropHandle; Parcel p; i.write(p); @@ -92,6 +95,8 @@ TEST(InputWindowInfo, Parcelling) { ASSERT_EQ(i.inputFeatures, i2.inputFeatures); ASSERT_EQ(i.displayId, i2.displayId); ASSERT_EQ(i.portalToDisplayId, i2.portalToDisplayId); + ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop); + ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle); } } // namespace test diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5c3fb05744..af27ca3571 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2009,8 +2009,24 @@ void Layer::commitChildList() { mDrawingParent = mCurrentParent; } +static wp extractLayerFromBinder(const wp& weakBinderHandle) { + if (weakBinderHandle == nullptr) { + return nullptr; + } + sp binderHandle = weakBinderHandle.promote(); + if (binderHandle == nullptr) { + return nullptr; + } + sp handle = static_cast(binderHandle.get()); + if (handle == nullptr) { + return nullptr; + } + return handle->owner; +} + void Layer::setInputInfo(const InputWindowInfo& info) { mCurrentState.inputInfo = info; + mCurrentState.touchableRegionCrop = extractLayerFromBinder(info.touchableRegionCropHandle); mCurrentState.modified = true; mCurrentState.inputInfoChanged = true; setTransactionFlags(eTransactionNeeded); @@ -2199,6 +2215,18 @@ InputWindowInfo Layer::fillInputInfo() { // bounds. info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop); info.visible = canReceiveInput(); + + auto cropLayer = mDrawingState.touchableRegionCrop.promote(); + if (info.replaceTouchableRegionWithCrop) { + if (cropLayer == nullptr) { + info.touchableRegion = Region(Rect{mScreenBounds}); + } else { + info.touchableRegion = Region(Rect{cropLayer->mScreenBounds}); + } + } else if (cropLayer != nullptr) { + info.touchableRegion = info.touchableRegion.intersect(Rect{cropLayer->mScreenBounds}); + } + return info; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 1afb9173f3..af50f5914b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -181,6 +181,7 @@ public: bool inputInfoChanged; InputWindowInfo inputInfo; + wp touchableRegionCrop; // The fields below this point are only used by BufferStateLayer Geometry active; -- cgit v1.2.3-59-g8ed1b From ee33b9fce52c5254e4134a56663d94b6c3474992 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 17 Jul 2019 15:04:02 -0700 Subject: InputWindow: use read/writeStrongBinder Still storing binder locally as a weak binder, but the plan is to remove read/writeWeakBinder APIs. This is because weak binders can't be promoted unless there is already a strong binder in a given process. Bug: 137785053 Test: atest libgui_tests libinput_tests Before and after: libgui_test: Passed: 202, Failed: 1, Ignored: 0, Assumption Failed: 0 libinput_tests: Passed: 74, Failed: 0, Ignored: 0, Assumption Failed: 0 The ToT failure is: [133/203] SurfaceTest#GetHdrSupport: FAILED (6ms) Change-Id: I4e952672885a035174152286c529d82f55d48326 --- libs/input/InputWindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libs/input/InputWindow.cpp') diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index 5a60347ed3..ec28757933 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -99,7 +99,7 @@ status_t InputWindowInfo::write(Parcel& output) const { applicationInfo.write(output); output.write(touchableRegion); output.writeBool(replaceTouchableRegionWithCrop); - output.writeWeakBinder(touchableRegionCropHandle); + output.writeStrongBinder(touchableRegionCropHandle.promote()); return OK; } @@ -142,7 +142,7 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { ret.applicationInfo = InputApplicationInfo::read(from); from.read(ret.touchableRegion); ret.replaceTouchableRegionWithCrop = from.readBool(); - ret.touchableRegionCropHandle = from.readWeakBinder(); + ret.touchableRegionCropHandle = from.readStrongBinder(); return ret; } -- cgit v1.2.3-59-g8ed1b