summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2010-09-27 14:52:15 -0700
committerJeff Brown <jeffbrown@google.com>2010-09-27 16:10:17 -0700
commite65041225ec0bbc3d67a3b70cdc6d598a5760043 (patch)
tree8eb92db22f21de0a2843aa39b9988d15e00233d9
parent464fb74e28b6d76d5e741abcdbb714eea2d9b4d1 (diff)
downloadframeworks_base-e65041225ec0bbc3d67a3b70cdc6d598a5760043.zip
frameworks_base-e65041225ec0bbc3d67a3b70cdc6d598a5760043.tar.gz
frameworks_base-e65041225ec0bbc3d67a3b70cdc6d598a5760043.tar.bz2
Add support for transferring touch focus.
Prerequisite for drag and drop. Change-Id: Iedbe93ed0f3e1c4083130fe66b4ba06d416afce0
-rw-r--r--include/ui/InputDispatcher.h11
-rw-r--r--libs/ui/InputDispatcher.cpp64
-rw-r--r--services/java/com/android/server/InputManager.java25
-rw-r--r--services/jni/com_android_server_InputManager.cpp21
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 },
};