Fix keyboard focus in VR

Consider this VirtualDisplay (VD) scenario:
HostActivity creates a VD which holds SettingsActivity. When EditText
on SettingsActivity is tapped, it gains focus.
On eventual taps, it loses focus i.e. the Window in VD loses focus and
the host activity in primary display gets the focus instead. This
happens because WM's TaskTapPointerEventListener.onPointerEvent()
is called on the default display only.

Root cause:
1. Tap detector isn't registered for non-default display.
2. Tap detector has no info on which displayId touch was received.
3. InputFlinger doesn't deliver InputMonitor events for
non-default displays (fixed in a separate CL)

Fixing above results in onPointerEvent(MotionEvent) to deliver the
Touch events successfully to VD. We restrict these changes to physical
multi-displays and VR VirtualDisplays (which uses virtual touch device).
[VrManagerService calls WMInternal.setVr2dDisplayId(int)]

In future, displayId should be part of InputEvent. Bug: 64258305

Bug: 62033391
Test: bit FrameworksServicesTests:com.android.server.wm.DisplayContentTests
Change-Id: I3626f4de5aa9bcf905da9abd39f3ab1baefc4c48
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 856e940..91eb55b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -31,10 +31,13 @@
 import org.junit.runner.RunWith;
 
 import android.content.res.Configuration;
+import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.DisplayMetrics;
 import android.util.SparseIntArray;
+import android.view.MotionEvent;
 
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -237,6 +240,52 @@
         assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
     }
 
+    /**
+     * Tests tapping on a stack in different display results in window gaining focus.
+     */
+    @Test
+    public void testInputEventBringsCorrectDisplayInFocus() throws Exception {
+        DisplayContent dc0 = sWm.getDefaultDisplayContentLocked();
+        // Create a second display
+        final DisplayContent dc1 = createNewDisplay();
+
+        // Add stack with activity.
+        final TaskStack stack0 = createTaskStackOnDisplay(dc0);
+        final Task task0 = createTaskInStack(stack0, 0 /* userId */);
+        final WindowTestUtils.TestAppWindowToken token =
+                new WindowTestUtils.TestAppWindowToken(dc0);
+        task0.addChild(token, 0);
+        dc0.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
+        sWm.registerPointerEventListener(dc0.mTapDetector);
+        final TaskStack stack1 = createTaskStackOnDisplay(dc1);
+        final Task task1 = createTaskInStack(stack1, 0 /* userId */);
+        final WindowTestUtils.TestAppWindowToken token1 =
+                new WindowTestUtils.TestAppWindowToken(dc0);
+        task1.addChild(token1, 0);
+        dc1.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
+        sWm.registerPointerEventListener(dc1.mTapDetector);
+
+        // tap on primary display (by sending ACTION_DOWN followed by ACTION_UP)
+        DisplayMetrics dm0 = dc0.getDisplayMetrics();
+        dc0.mTapDetector.onPointerEvent(
+                createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, true));
+        dc0.mTapDetector.onPointerEvent(
+                createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, false));
+
+        // Check focus is on primary display.
+        assertEquals(sWm.mCurrentFocus, dc0.findFocusedWindow());
+
+        // Tap on secondary display
+        DisplayMetrics dm1 = dc1.getDisplayMetrics();
+        dc1.mTapDetector.onPointerEvent(
+                createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, true));
+        dc1.mTapDetector.onPointerEvent(
+                createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, false));
+
+        // Check focus is on secondary.
+        assertEquals(sWm.mCurrentFocus, dc1.findFocusedWindow());
+    }
+
     @Test
     @Ignore
     public void testFocusedWindowMultipleDisplays() throws Exception {
@@ -355,4 +404,18 @@
         }
         assertTrue(actualWindows.isEmpty());
     }
+
+    private MotionEvent createTapEvent(float x, float y, boolean isDownEvent) {
+        final long downTime = SystemClock.uptimeMillis();
+        final long eventTime = SystemClock.uptimeMillis() + 100;
+        final int metaState = 0;
+
+        return MotionEvent.obtain(
+                downTime,
+                eventTime,
+                isDownEvent ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP,
+                x,
+                y,
+                metaState);
+    }
 }