diff options
| author | 2017-08-02 20:33:02 +0000 | |
|---|---|---|
| committer | 2017-08-02 20:33:02 +0000 | |
| commit | 986995d481a6ecff1285a05a060b537b64cfe61d (patch) | |
| tree | d019845abe84247492e356654cb0c3190679afc6 | |
| parent | 615f9e1277a6a3bad00972bdc978c6f5a5b2faa0 (diff) | |
| parent | e1cfcf4c4d15417bc912d36d487b4454c19b30fa (diff) | |
Merge "Fix keyboard focus in VR" into oc-dr1-dev
21 files changed, 185 insertions, 37 deletions
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index ed223d1fd503..d2e3510ee3b1 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -16,10 +16,6 @@ package android.inputmethodservice; -import com.android.internal.os.HandlerCaller; -import com.android.internal.os.SomeArgs; -import com.android.internal.view.IInputMethodSession; - import android.content.Context; import android.graphics.Rect; import android.os.Bundle; @@ -34,9 +30,13 @@ import android.view.InputEventReceiver; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.InputMethodSession; -import android.view.inputmethod.CursorAnchorInfo; + +import com.android.internal.os.HandlerCaller; +import com.android.internal.os.SomeArgs; +import com.android.internal.view.IInputMethodSession; class IInputMethodSessionWrapper extends IInputMethodSession.Stub implements HandlerCaller.Callback { @@ -218,7 +218,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { if (mInputMethodSession == null) { // The session has been finished. finishInputEvent(event, false); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index e4d3142ccefe..ef8256bb32ca 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -268,7 +268,7 @@ public abstract class WallpaperService extends Service { } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { boolean handled = false; try { if (event instanceof MotionEvent diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java index 20ab539f52d2..c566a653da42 100644 --- a/core/java/android/view/InputEventReceiver.java +++ b/core/java/android/view/InputEventReceiver.java @@ -111,9 +111,10 @@ public abstract class InputEventReceiver { * to indicate whether the event was handled. No new input events will be received * until {@link #finishInputEvent} is called. * + * @param displayId The display id on which input event triggered. * @param event The input event that was received. */ - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { finishInputEvent(event, false); } @@ -180,9 +181,9 @@ public abstract class InputEventReceiver { // Called from native code. @SuppressWarnings("unused") - private void dispatchInputEvent(int seq, InputEvent event) { + private void dispatchInputEvent(int seq, InputEvent event, int displayId) { mSeqMap.put(event.getSequenceNumber(), seq); - onInputEvent(event); + onInputEvent(event, displayId); } // Called from native code. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e38a55f76b7d..7ace841d270c 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6756,7 +6756,7 @@ public final class ViewRootImpl implements ViewParent, } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { enqueueInputEvent(event, this, 0, true); } diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java index 4c9cf40beb8d..98f8dc8e3a6d 100644 --- a/core/java/android/view/WindowManagerInternal.java +++ b/core/java/android/view/WindowManagerInternal.java @@ -347,4 +347,11 @@ public abstract class WindowManagerInternal { * Requests the window manager to recompute the windows for accessibility. */ public abstract void computeWindowsForAccessibility(); + + /** + * Called after virtual display Id is updated by + * {@link com.android.server.vr.Vr2dDisplay} with a specific + * {@param vr2dDisplayId}. + */ + public abstract void setVr2dDisplayId(int vr2dDisplayId); } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 668d25e74276..49b7ed8bac0e 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -16,6 +16,7 @@ package android.view; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; @@ -616,7 +617,16 @@ public interface WindowManagerPolicy { * 2. motionEvent will be recycled after onPointerEvent returns so if it is needed later a * copy() must be made and the copy must be recycled. **/ - public void onPointerEvent(MotionEvent motionEvent); + void onPointerEvent(MotionEvent motionEvent); + + /** + * @see #onPointerEvent(MotionEvent) + **/ + default void onPointerEvent(MotionEvent motionEvent, int displayId) { + if (displayId == DEFAULT_DISPLAY) { + onPointerEvent(motionEvent); + } + } } /** Window has been added to the screen. */ diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index 8293cd8ff88d..084a3d13a0ed 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -233,8 +233,9 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, for (;;) { uint32_t seq; InputEvent* inputEvent; + int32_t displayId; status_t status = mInputConsumer.consume(&mInputEventFactory, - consumeBatches, frameTime, &seq, &inputEvent); + consumeBatches, frameTime, &seq, &inputEvent, &displayId); if (status) { if (status == WOULD_BLOCK) { if (!skipCallbacks && !mBatchedInputEventPending @@ -311,7 +312,8 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName()); } env->CallVoidMethod(receiverObj.get(), - gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj); + gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj, + displayId); if (env->ExceptionCheck()) { ALOGE("Exception dispatching input event."); skipCallbacks = true; @@ -417,7 +419,7 @@ int register_android_view_InputEventReceiver(JNIEnv* env) { gInputEventReceiverClassInfo.dispatchInputEvent = GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, - "dispatchInputEvent", "(ILandroid/view/InputEvent;)V"); + "dispatchInputEvent", "(ILandroid/view/InputEvent;I)V"); gInputEventReceiverClassInfo.dispatchBatchedInputEventPending = GetMethodIDOrDie(env, gInputEventReceiverClassInfo.clazz, "dispatchBatchedInputEventPending", "()V"); diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index 3bd6917aedfa..4769257e5551 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -39,6 +39,8 @@ namespace android { // Log debug messages about the dispatch cycle. static const bool kDebugDispatchCycle = false; +// Display id for default(primary) display. +static const int32_t kDefaultDisplayId = 0; static struct { jclass clazz; @@ -136,6 +138,7 @@ status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent publishedSeq = mNextPublishedSeq++; status_t status = mInputPublisher.publishMotionEvent(publishedSeq, event->getDeviceId(), event->getSource(), + kDefaultDisplayId /* TODO(multi-display): propagate display id */, event->getAction(), event->getActionButton(), event->getFlags(), event->getEdgeFlags(), event->getMetaState(), event->getButtonState(), event->getXOffset(), event->getYOffset(), diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java index 07cfbda7ac2b..df87e0f28cd9 100644 --- a/media/java/android/media/tv/ITvInputSessionWrapper.java +++ b/media/java/android/media/tv/ITvInputSessionWrapper.java @@ -367,7 +367,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { if (mTvInputSessionImpl == null) { // The session has been finished. finishInputEvent(event, false); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java index 6733421a8d0e..abc5667251ea 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java @@ -65,7 +65,7 @@ public class InputConsumerController { } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { boolean handled = true; try { // To be implemented for input handling over Pip windows diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index e3cf459774e9..61ecee38dfdb 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4184,7 +4184,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { boolean handled = false; try { if (event instanceof MotionEvent diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java index 69d8ca68522f..8f50a39a5424 100644 --- a/services/core/java/com/android/server/vr/Vr2dDisplay.java +++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java @@ -24,6 +24,7 @@ import android.service.vr.IPersistentVrStateCallbacks; import android.service.vr.IVrManager; import android.util.Log; import android.view.Surface; +import android.view.WindowManagerInternal; import com.android.server.vr.VrManagerService; @@ -74,6 +75,7 @@ class Vr2dDisplay { public static final int MIN_VR_DISPLAY_DPI = 1; private final ActivityManagerInternal mActivityManagerInternal; + private final WindowManagerInternal mWindowManagerInternal; private final DisplayManager mDisplayManager; private final IVrManager mVrManager; private final Object mVdLock = new Object(); @@ -103,9 +105,11 @@ class Vr2dDisplay { private boolean mBootsToVr = false; // The device boots into VR (standalone VR device) public Vr2dDisplay(DisplayManager displayManager, - ActivityManagerInternal activityManagerInternal, IVrManager vrManager) { + ActivityManagerInternal activityManagerInternal, + WindowManagerInternal windowManagerInternal, IVrManager vrManager) { mDisplayManager = displayManager; mActivityManagerInternal = activityManagerInternal; + mWindowManagerInternal = windowManagerInternal; mVrManager = vrManager; mVirtualDisplayWidth = DEFAULT_VIRTUAL_DISPLAY_WIDTH; mVirtualDisplayHeight = DEFAULT_VIRTUAL_DISPLAY_HEIGHT; @@ -296,13 +300,12 @@ class Vr2dDisplay { UNIQUE_DISPLAY_ID); if (mVirtualDisplay != null) { - mActivityManagerInternal.setVr2dDisplayId( - mVirtualDisplay.getDisplay().getDisplayId()); + updateDisplayId(mVirtualDisplay.getDisplay().getDisplayId()); // Now create the ImageReader to supply a Surface to the new virtual display. startImageReader(); } else { Log.w(TAG, "Virtual display id is null after createVirtualDisplay"); - mActivityManagerInternal.setVr2dDisplayId(INVALID_DISPLAY); + updateDisplayId(INVALID_DISPLAY); return; } } @@ -310,6 +313,11 @@ class Vr2dDisplay { Log.i(TAG, "VD created: " + mVirtualDisplay); } + private void updateDisplayId(int displayId) { + mActivityManagerInternal.setVr2dDisplayId(displayId); + mWindowManagerInternal.setVr2dDisplayId(displayId); + } + /** * Stops the virtual display with a {@link #STOP_VIRTUAL_DISPLAY_DELAY_MILLIS} timeout. * The timeout prevents the virtual display from bouncing in cases where VrMode goes in and out @@ -325,7 +333,7 @@ class Vr2dDisplay { } else { Log.i(TAG, "Stopping Virtual Display"); synchronized (mVdLock) { - mActivityManagerInternal.setVr2dDisplayId(INVALID_DISPLAY); + updateDisplayId(INVALID_DISPLAY); setSurfaceLocked(null); // clean up and release the surface first. if (mVirtualDisplay != null) { mVirtualDisplay.release(); diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index 29968781b26d..030b74cc7ea8 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -56,6 +56,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; +import android.view.WindowManagerInternal; import com.android.internal.R; import com.android.internal.util.DumpUtils; @@ -627,8 +628,11 @@ public class VrManagerService extends SystemService implements EnabledComponentC DisplayManager dm = (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE); - ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); - mVr2dDisplay = new Vr2dDisplay(dm, ami, mVrManager); + mVr2dDisplay = new Vr2dDisplay( + dm, + LocalServices.getService(ActivityManagerInternal.class), + LocalServices.getService(WindowManagerInternal.class), + mVrManager); mVr2dDisplay.init(getContext(), mBootsToVr); IntentFilter intentFilter = new IntentFilter(); diff --git a/services/core/java/com/android/server/wm/PointerEventDispatcher.java b/services/core/java/com/android/server/wm/PointerEventDispatcher.java index 6b0e4c9f010a..484987ec127e 100644 --- a/services/core/java/com/android/server/wm/PointerEventDispatcher.java +++ b/services/core/java/com/android/server/wm/PointerEventDispatcher.java @@ -36,11 +36,11 @@ public class PointerEventDispatcher extends InputEventReceiver { } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { try { if (event instanceof MotionEvent && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { - final MotionEvent motionEvent = (MotionEvent)event; + final MotionEvent motionEvent = (MotionEvent) event; PointerEventListener[] listeners; synchronized (mListeners) { if (mListenersArray == null) { @@ -50,7 +50,7 @@ public class PointerEventDispatcher extends InputEventReceiver { listeners = mListenersArray; } for (int i = 0; i < listeners.length; ++i) { - listeners[i].onPointerEvent(motionEvent); + listeners[i].onPointerEvent(motionEvent, displayId); } } } finally { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 36fa3a733987..40528d06f665 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -18,6 +18,7 @@ package com.android.server.wm; import android.content.res.Configuration; import android.graphics.Rect; +import android.hardware.display.DisplayManager; import android.hardware.power.V1_0.PowerHint; import android.os.Binder; import android.os.Debug; @@ -243,12 +244,24 @@ class RootWindowContainer extends WindowContainer<DisplayContent> { displayId, displayInfo); mService.configureDisplayPolicyLocked(dc); - // TODO(multi-display): Create an input channel for each display with touch capability. - if (displayId == DEFAULT_DISPLAY && mService.canDispatchPointerEvents()) { - dc.mTapDetector = new TaskTapPointerEventListener( - mService, dc); + // Tap Listeners are supported for: + // 1. All physical displays (multi-display). + // 2. VirtualDisplays that support virtual touch input. (Only VR for now) + // TODO(multi-display): Support VirtualDisplays with no virtual touch input. + if ((display.getType() != Display.TYPE_VIRTUAL + || (display.getType() == Display.TYPE_VIRTUAL + // Only VR VirtualDisplays + && displayId == mService.mVr2dDisplayId)) + && mService.canDispatchPointerEvents()) { + if (DEBUG_DISPLAY) { + Slog.d(TAG, + "Registering PointerEventListener for DisplayId: " + displayId); + } + dc.mTapDetector = new TaskTapPointerEventListener(mService, dc); mService.registerPointerEventListener(dc.mTapDetector); - mService.registerPointerEventListener(mService.mMousePositionTracker); + if (displayId == DEFAULT_DISPLAY) { + mService.registerPointerEventListener(mService.mMousePositionTracker); + } } } diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 0c68e2ca6d77..c58212cd8235 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -133,7 +133,7 @@ class TaskPositioner implements DimLayer.DimLayerUser { } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { if (!(event instanceof MotionEvent) || (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) { return; diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java index dd9ba7355d7c..42a2d9df5fb5 100644 --- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java +++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java @@ -24,6 +24,7 @@ import android.view.WindowManagerPolicy.PointerEventListener; import com.android.server.wm.WindowManagerService.H; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.PointerIcon.TYPE_NOT_SPECIFIED; import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW; import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW; @@ -45,6 +46,13 @@ public class TaskTapPointerEventListener implements PointerEventListener { } @Override + public void onPointerEvent(MotionEvent motionEvent, int displayId) { + if (displayId == getDisplayId()) { + onPointerEvent(motionEvent); + } + } + + @Override public void onPointerEvent(MotionEvent motionEvent) { final int action = motionEvent.getAction(); switch (action & MotionEvent.ACTION_MASK) { @@ -104,4 +112,8 @@ public class TaskTapPointerEventListener implements PointerEventListener { mTouchExcludeRegion.set(newRegion); } } + + private int getDisplayId() { + return mDisplayContent.getDisplayId(); + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2caac7a2be3f..b0775dd3a859 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -79,6 +79,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; @@ -357,6 +358,8 @@ public class WindowManagerService extends IWindowManager.Stub final private KeyguardDisableHandler mKeyguardDisableHandler; boolean mKeyguardGoingAway; + // VR Vr2d Display Id. + int mVr2dDisplayId = INVALID_DISPLAY; private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -764,7 +767,7 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { boolean handled = false; try { if (mDragState == null) { @@ -7542,6 +7545,16 @@ public class WindowManagerService extends IWindowManager.Stub accessibilityController.performComputeChangedWindowsNotLocked(); } } + + @Override + public void setVr2dDisplayId(int vr2dDisplayId) { + if (DEBUG_DISPLAY) { + Slog.d(TAG, "setVr2dDisplayId called for: " + vr2dDisplayId); + } + synchronized (WindowManagerService.this) { + mVr2dDisplayId = vr2dDisplayId; + } + } } void registerAppFreezeListener(AppFreezeListener listener) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 34ff9e8e338f..81c5164534a5 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2038,7 +2038,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP super(inputChannel, mService.mH.getLooper()); } @Override - public void onInputEvent(InputEvent event) { + public void onInputEvent(InputEvent event, int displayId) { finishInputEvent(event, true); } } 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 856e94055ed5..91eb55ba3fcf 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.Test; 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 @@ public class DisplayContentTests extends WindowTestsBase { 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 @@ public class DisplayContentTests extends WindowTestsBase { } 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); + } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java index 828d405b5e3b..95adc9cd5a1a 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -18,6 +18,10 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM; + +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -39,6 +43,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.view.Display; import android.view.IWindowManager; +import android.view.InputChannel; import android.view.KeyEvent; import android.view.WindowManager; import android.view.WindowManagerPolicy; @@ -91,7 +96,14 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { }).when(am).notifyKeyguardFlagsChanged(any()); } - sWm = WindowManagerService.main(context, mock(InputManagerService.class), true, false, + InputManagerService ims = mock(InputManagerService.class); + // InputChannel is final and can't be mocked. + InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM); + if (input != null && input.length > 1) { + doReturn(input[1]).when(ims).monitorInput(anyString()); + } + + sWm = WindowManagerService.main(context, ims, true, false, false, new TestWindowManagerPolicy()); } return sWm; |