Track input state when transferring touch focus.

Copies the input state to the destination window and sends synthesic
cancelation events to the source window.

Change-Id: Ia75820b0d756ed5d6cd22dce7830251ac85141ed
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 2c22cad..63185d3 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -757,6 +757,9 @@
         // Clears the current state.
         void clear();
 
+        // Copies pointer-related parts of the input state to another instance.
+        void copyPointerStateTo(InputState& other) const;
+
     private:
         struct KeyMemento {
             int32_t deviceId;
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 8e9eb21..52e488a 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -2668,6 +2668,18 @@
             return false;
         }
 
+        ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
+        ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
+        if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
+            sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex);
+            sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
+
+            fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
+            synthesizeCancelationEventsForConnectionLocked(fromConnection,
+                    InputState::CANCEL_POINTER_EVENTS,
+                    "transferring touch focus from this window to another window");
+        }
+
 #if DEBUG_FOCUS
         logDispatchStateLocked();
 #endif
@@ -3404,6 +3416,24 @@
     mMotionMementos.clear();
 }
 
+void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
+    for (size_t i = 0; i < mMotionMementos.size(); i++) {
+        const MotionMemento& memento = mMotionMementos.itemAt(i);
+        if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
+            for (size_t j = 0; j < other.mMotionMementos.size(); ) {
+                const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j);
+                if (memento.deviceId == otherMemento.deviceId
+                        && memento.source == otherMemento.source) {
+                    other.mMotionMementos.removeAt(j);
+                } else {
+                    j += 1;
+                }
+            }
+            other.mMotionMementos.push(memento);
+        }
+    }
+}
+
 bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource,
         CancelationOptions options) {
     switch (options) {
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 29815f6..e15e8d8 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -1233,7 +1233,6 @@
 static jboolean android_server_InputManager_nativeTransferTouchFocus(JNIEnv* env,
         jclass clazz, jobject fromChannelObj, jobject toChannelObj) {
     if (checkInputManagerUnitialized(env)) {
-        LOGD("input manager uninitialized; bailing");
         return false;
     }
 
@@ -1243,7 +1242,6 @@
             android_view_InputChannel_getInputChannel(env, toChannelObj);
 
     if (fromChannel == NULL || toChannel == NULL) {
-        LOGD("bailing because from=%p to=%p", fromChannel, toChannel);
         return false;
     }