diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h index cc1601298..8d4654f95 100644 --- a/include/ui/InputDispatcher.h +++ b/include/ui/InputDispatcher.h @@ -355,6 +355,14 @@ public: */ virtual void setInputDispatchMode(bool enabled, bool frozen) = 0; + /* Transfers touch focus from the window associated with one channel to the + * window associated with the other channel. + * + * Returns true on success. False if the window did not actually have touch focus. + */ + virtual bool transferTouchFocus(const sp& fromChannel, + const sp& toChannel) = 0; + /* Registers or unregister input channels that may be used as targets for input events. * If monitor is true, the channel will receive a copy of all input events. * @@ -409,6 +417,9 @@ public: virtual void setFocusedApplication(const InputApplication* inputApplication); virtual void setInputDispatchMode(bool enabled, bool frozen); + virtual bool transferTouchFocus(const sp& fromChannel, + const sp& toChannel); + virtual status_t registerInputChannel(const sp& inputChannel, bool monitor); virtual status_t unregisterInputChannel(const sp& inputChannel); diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 5da167675..9e78a4a4b 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -2464,6 +2464,70 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { } } +bool InputDispatcher::transferTouchFocus(const sp& fromChannel, + const sp& toChannel) { +#if DEBUG_FOCUS + LOGD("transferTouchFocus: fromChannel=%s, toChannel=%s", + fromChannel->getName().string(), toChannel->getName().string()); +#endif + { // acquire lock + AutoMutex _l(mLock); + + const InputWindow* fromWindow = getWindowLocked(fromChannel); + const InputWindow* toWindow = getWindowLocked(toChannel); + if (! fromWindow || ! toWindow) { +#if DEBUG_FOCUS + LOGD("Cannot transfer focus because from or to window not found."); +#endif + return false; + } + if (fromWindow == toWindow) { +#if DEBUG_FOCUS + LOGD("Trivial transfer to same window."); +#endif + return true; + } + + bool found = false; + for (size_t i = 0; i < mTouchState.windows.size(); i++) { + const TouchedWindow& touchedWindow = mTouchState.windows[i]; + if (touchedWindow.window == fromWindow) { + int32_t oldTargetFlags = touchedWindow.targetFlags; + BitSet32 pointerIds = touchedWindow.pointerIds; + + mTouchState.windows.removeAt(i); + + int32_t newTargetFlags = 0; + if (oldTargetFlags & InputTarget::FLAG_FOREGROUND) { + newTargetFlags |= InputTarget::FLAG_FOREGROUND; + if (toWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH) { + newTargetFlags |= InputTarget::FLAG_SPLIT; + } + } + mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds); + + found = true; + break; + } + } + + if (! found) { +#if DEBUG_FOCUS + LOGD("Focus transfer failed because from window did not have focus."); +#endif + return false; + } + +#if DEBUG_FOCUS + logDispatchStateLocked(); +#endif + } // release lock + + // Wake up poll loop since it may need to make new input dispatching choices. + mLooper->wake(); + return true; +} + void InputDispatcher::logDispatchStateLocked() { String8 dump; dumpDispatchStateLocked(dump);