Add support for transferring touch focus.
Prerequisite for drag and drop. Change-Id: Iedbe93ed0f3e1c4083130fe66b4ba06d416afce0
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user