Add support for transferring touch focus.

Prerequisite for drag and drop.

Change-Id: Iedbe93ed0f3e1c4083130fe66b4ba06d416afce0
This commit is contained in:
Jeff Brown
2010-09-27 14:52:15 -07:00
parent 464fb74e28
commit e65041225e
4 changed files with 121 additions and 0 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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 },
};