diff options
-rw-r--r-- | include/ui/InputDispatcher.h | 11 | ||||
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 64 | ||||
-rw-r--r-- | services/java/com/android/server/InputManager.java | 25 | ||||
-rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 21 |
4 files changed, 121 insertions, 0 deletions
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h index cc16012..8d4654f 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<InputChannel>& fromChannel, + const sp<InputChannel>& 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<InputChannel>& fromChannel, + const sp<InputChannel>& toChannel); + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor); virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 5da1676..9e78a4a 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<InputChannel>& fromChannel, + const sp<InputChannel>& 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); diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index 29ca9a4..fe306b3 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -77,6 +77,8 @@ public class InputManager { private static native InputDevice nativeGetInputDevice(int deviceId); private static native void nativeGetInputConfiguration(Configuration configuration); private static native int[] nativeGetInputDeviceIds(); + private static native boolean nativeTransferTouchFocus(InputChannel fromChannel, + InputChannel toChannel); private static native String nativeDump(); // Input event injection constants defined in InputDispatcher.h. @@ -320,6 +322,29 @@ public class InputManager { nativeSetInputDispatchMode(enabled, frozen); } + /** + * Atomically transfers touch focus from one window to another as identified by + * their input channels. It is possible for multiple windows to have + * touch focus if they support split touch dispatch + * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this + * method only transfers touch focus of the specified window without affecting + * other windows that may also have touch focus at the same time. + * @param fromChannel The channel of a window that currently has touch focus. + * @param toChannel The channel of the window that should receive touch focus in + * place of the first. + * @return True if the transfer was successful. False if the window with the + * specified channel did not actually have touch focus at the time of the request. + */ + public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) { + if (fromChannel == null) { + throw new IllegalArgumentException("fromChannel must not be null."); + } + if (toChannel == null) { + throw new IllegalArgumentException("toChannel must not be null."); + } + return nativeTransferTouchFocus(fromChannel, toChannel); + } + public void dump(PrintWriter pw) { String dumpStr = nativeDump(); if (dumpStr != null) { diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 6f52f24..e1e54fc 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -1286,6 +1286,25 @@ static void android_server_InputManager_nativeGetInputConfiguration(JNIEnv* env, env->SetIntField(configObj, gConfigurationClassInfo.navigation, config.navigation); } +static jboolean android_server_InputManager_nativeTransferTouchFocus(JNIEnv* env, + jclass clazz, jobject fromChannelObj, jobject toChannelObj) { + if (checkInputManagerUnitialized(env)) { + return false; + } + + sp<InputChannel> fromChannel = + android_view_InputChannel_getInputChannel(env, fromChannelObj); + sp<InputChannel> toChannel = + android_view_InputChannel_getInputChannel(env, toChannelObj); + + if (fromChannel == NULL || toChannel == NULL) { + return false; + } + + return gNativeInputManager->getInputManager()->getDispatcher()-> + transferTouchFocus(fromChannel, toChannel); +} + static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) { if (checkInputManagerUnitialized(env)) { return NULL; @@ -1334,6 +1353,8 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) android_server_InputManager_nativeGetInputDeviceIds }, { "nativeGetInputConfiguration", "(Landroid/content/res/Configuration;)V", (void*) android_server_InputManager_nativeGetInputConfiguration }, + { "nativeTransferTouchFocus", "(Landroid/view/InputChannel;Landroid/view/InputChannel;)Z", + (void*) android_server_InputManager_nativeTransferTouchFocus }, { "nativeDump", "()Ljava/lang/String;", (void*) android_server_InputManager_nativeDump }, }; |