From 3da19deb307571959324fd27ef0a9215e314cb6b Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 11 Jul 2022 16:00:23 +0000 Subject: [PATCH] Prevent displays that are disabled from receiving input For foldable devices with two displays, both displays often map to the same layer stack. In this case, the we expect only one of the two displays to be used at once, and the other should be disabled. When the device is folded/unfoled, the display that is enabled will change. When two displays map to the same layer stack, it is currently difficult to identify the display which the layer stack should be associated with. Picking the incorrect display will result in issues with input dispatching. For now, we get around the one-to-many mapping between layer stacks and displays for input by preventing displays that are disabled from receiving input, assuming only one display is enabled at a time for a given layer stack. Bug: 238122363 Test: None Change-Id: I7cc5c4296bb8d891c89fc334f13988dd39d936f3 --- .../server/display/LogicalDisplay.java | 6 ++- .../server/display/LogicalDisplayTest.java | 46 +++++++++++++++++-- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 05341e0f876eb..dedc56ac9b417 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -523,10 +523,12 @@ final class LogicalDisplay { // Set the layer stack. device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack); // Also inform whether the device is the same one sent to inputflinger for its layerstack. + // Prevent displays that are disabled from receiving input. // TODO(b/188914255): Remove once input can dispatch against device vs layerstack. device.setDisplayFlagsLocked(t, - device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE - ? SurfaceControl.DISPLAY_RECEIVES_INPUT : 0); + (isEnabled() && device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE) + ? SurfaceControl.DISPLAY_RECEIVES_INPUT + : 0); // Set the color mode and allowed display mode. if (device == mPrimaryDisplayDevice) { diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java index ece0a627f0512..b0738fdb78d0c 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java @@ -17,7 +17,11 @@ package com.android.server.display; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.PropertyInvalidatedCache; @@ -45,18 +49,21 @@ public class LogicalDisplayTest { private LogicalDisplay mLogicalDisplay; private DisplayDevice mDisplayDevice; + private final DisplayDeviceInfo mDisplayDeviceInfo = new DisplayDeviceInfo(); @Before public void setUp() { // Share classloader to allow package private access. System.setProperty("dexmaker.share_classloader", "true"); mDisplayDevice = mock(DisplayDevice.class); - DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo(); - displayDeviceInfo.width = DISPLAY_WIDTH; - displayDeviceInfo.height = DISPLAY_HEIGHT; - displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice); - when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(displayDeviceInfo); + + mDisplayDeviceInfo.copyFrom(new DisplayDeviceInfo()); + mDisplayDeviceInfo.width = DISPLAY_WIDTH; + mDisplayDeviceInfo.height = DISPLAY_HEIGHT; + mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; + mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL; + when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(mDisplayDeviceInfo); // Disable binder caches in this process. PropertyInvalidatedCache.disableForTestMode(); @@ -103,4 +110,33 @@ public class LogicalDisplayTest { mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); } + + @Test + public void testDisplayInputFlags() { + SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); + mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); + verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT)); + reset(t); + + mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_NONE; + mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); + verify(t).setDisplayFlags(any(), eq(0)); + reset(t); + + mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_VIRTUAL; + mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); + verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT)); + reset(t); + + mLogicalDisplay.setPhase(LogicalDisplay.DISPLAY_PHASE_DISABLED); + mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); + verify(t).setDisplayFlags(any(), eq(0)); + reset(t); + + mLogicalDisplay.setPhase(LogicalDisplay.DISPLAY_PHASE_ENABLED); + mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; + mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); + verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT)); + reset(t); + } }