Loading services/core/java/com/android/server/display/LocalDisplayAdapter.java +33 −8 Original line number Diff line number Diff line Loading @@ -69,21 +69,27 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>(); @SuppressWarnings("unused") // Becomes active at instantiation time. private PhysicalDisplayEventReceiver mPhysicalDisplayEventReceiver; private final Injector mInjector; // Called with SyncRoot lock held. public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener) { this(syncRoot, context, handler, listener, new Injector()); } LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, Injector injector) { super(syncRoot, context, handler, listener, TAG); mInjector = injector; } @Override public void registerLocked() { super.registerLocked(); mPhysicalDisplayEventReceiver = new PhysicalDisplayEventReceiver(getHandler().getLooper()); mInjector.setDisplayEventListenerLocked(getHandler().getLooper(), new LocalDisplayEventListener()); for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) { tryConnectDisplayLocked(physicalDisplayId); Loading Loading @@ -1052,12 +1058,33 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } private final class PhysicalDisplayEventReceiver extends DisplayEventReceiver { PhysicalDisplayEventReceiver(Looper looper) { public static class Injector { private ProxyDisplayEventReceiver mReceiver; public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) { mReceiver = new ProxyDisplayEventReceiver(looper, listener); } } public interface DisplayEventListener { void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected); void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId); } public static final class ProxyDisplayEventReceiver extends DisplayEventReceiver { private final DisplayEventListener mListener; ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) { super(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_DISPATCH); mListener = listener; } public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { mListener.onHotplug(timestampNanos, physicalDisplayId, connected); } public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { mListener.onConfigChanged(timestampNanos, physicalDisplayId, configId); } } @Override private final class LocalDisplayEventListener implements DisplayEventListener { public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { synchronized (getSyncRoot()) { if (connected) { Loading @@ -1067,8 +1094,6 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } } @Override public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { if (DEBUG) { Slog.d(TAG, "onConfigChanged(" Loading services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +69 −6 Original line number Diff line number Diff line Loading @@ -83,6 +83,8 @@ public class LocalDisplayAdapterTest { private LinkedList<DisplayAddress.Physical> mAddresses = new LinkedList<>(); private Injector mInjector; @Before public void setUp() throws Exception { mMockitoSession = mockitoSession() Loading @@ -94,8 +96,9 @@ public class LocalDisplayAdapterTest { doReturn(mMockedResources).when(mMockedContext).getResources(); LocalServices.removeServiceForTest(LightsManager.class); LocalServices.addService(LightsManager.class, mMockedLightsManager); mInjector = new Injector(); mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler, mListener); mListener, mInjector); spyOn(mAdapter); doReturn(mMockedContext).when(mAdapter).getOverlayContext(); } Loading Loading @@ -222,7 +225,7 @@ public class LocalDisplayAdapterTest { display.configs = configs; display.activeConfig = 1; setUpDisplay(display); mAdapter.registerLocked(); mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(SurfaceControl.getActiveConfig(display.token)).isEqualTo(1); Loading Loading @@ -272,7 +275,7 @@ public class LocalDisplayAdapterTest { new int[Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS], 1000, 1000, 0); display.hdrCapabilities = changedHdrCapabilities; setUpDisplay(display); mAdapter.registerLocked(); mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(mListener.addedDisplays.size()).isEqualTo(1); Loading Loading @@ -308,7 +311,7 @@ public class LocalDisplayAdapterTest { final int[] changedColorModes = new int[]{Display.COLOR_MODE_DEFAULT}; display.colorModes = changedColorModes; setUpDisplay(display); mAdapter.registerLocked(); mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(mListener.addedDisplays.size()).isEqualTo(1); Loading @@ -322,6 +325,35 @@ public class LocalDisplayAdapterTest { assertThat(displayDeviceInfo.supportedColorModes).isEqualTo(changedColorModes); } @Test public void testDisplayChange_withStaleDesiredDisplayConfigSpecs() throws Exception { SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[]{ createFakeDisplayConfig(1920, 1080, 60f), createFakeDisplayConfig(1920, 1080, 50f) }; final int activeConfig = 0; FakeDisplay display = new FakeDisplay(PORT_A, configs, activeConfig); display.desiredDisplayConfigSpecs.defaultConfig = 1; setUpDisplay(display); updateAvailableDisplays(); mAdapter.registerLocked(); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); // Change the display display.configs = new SurfaceControl.DisplayConfig[]{ createFakeDisplayConfig(1920, 1080, 60f) }; // SurfaceFlinger can return a stale defaultConfig. Make sure this doesn't // trigger ArrayOutOfBoundsException. display.desiredDisplayConfigSpecs.defaultConfig = 1; setUpDisplay(display); updateAvailableDisplays(); mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); } private void assertDisplayDpi(DisplayDeviceInfo info, int expectedPort, float expectedXdpi, float expectedYDpi, Loading Loading @@ -356,6 +388,8 @@ public class LocalDisplayAdapterTest { public int[] colorModes = new int[]{ Display.COLOR_MODE_DEFAULT }; public Display.HdrCapabilities hdrCapabilities = new Display.HdrCapabilities(new int[0], 1000, 1000, 0); public SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs = new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f); private FakeDisplay(int port) { this.address = createDisplayAddress(port); Loading Loading @@ -387,7 +421,7 @@ public class LocalDisplayAdapterTest { () -> SurfaceControl.getDisplayColorModes(display.token)); doReturn(display.hdrCapabilities).when( () -> SurfaceControl.getHdrCapabilities(display.token)); doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f)) doReturn(display.desiredDisplayConfigSpecs) .when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token)); } Loading Loading @@ -422,7 +456,7 @@ public class LocalDisplayAdapterTest { return config; } private void waitForHandlerToComplete(Handler handler, long waitTimeMs) private static void waitForHandlerToComplete(Handler handler, long waitTimeMs) throws InterruptedException { final Object lock = new Object(); synchronized (lock) { Loading @@ -435,6 +469,35 @@ public class LocalDisplayAdapterTest { } } private class HotplugTransmitter { private final Handler mHandler; private final LocalDisplayAdapter.DisplayEventListener mListener; HotplugTransmitter(Looper looper, LocalDisplayAdapter.DisplayEventListener listener) { mHandler = new Handler(looper); mListener = listener; } public void sendHotplug(FakeDisplay display, boolean connected) throws InterruptedException { mHandler.post(() -> mListener.onHotplug(/* timestampNanos = */ 0, display.address.getPhysicalDisplayId(), connected)); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); } } private class Injector extends LocalDisplayAdapter.Injector { private HotplugTransmitter mTransmitter; @Override public void setDisplayEventListenerLocked(Looper looper, LocalDisplayAdapter.DisplayEventListener listener) { mTransmitter = new HotplugTransmitter(looper, listener); } public HotplugTransmitter getTransmitter() { return mTransmitter; } } private class TestListener implements DisplayAdapter.Listener { public ArrayList<DisplayDevice> addedDisplays = new ArrayList<>(); public ArrayList<DisplayDevice> changedDisplays = new ArrayList<>(); Loading Loading
services/core/java/com/android/server/display/LocalDisplayAdapter.java +33 −8 Original line number Diff line number Diff line Loading @@ -69,21 +69,27 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>(); @SuppressWarnings("unused") // Becomes active at instantiation time. private PhysicalDisplayEventReceiver mPhysicalDisplayEventReceiver; private final Injector mInjector; // Called with SyncRoot lock held. public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener) { this(syncRoot, context, handler, listener, new Injector()); } LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener, Injector injector) { super(syncRoot, context, handler, listener, TAG); mInjector = injector; } @Override public void registerLocked() { super.registerLocked(); mPhysicalDisplayEventReceiver = new PhysicalDisplayEventReceiver(getHandler().getLooper()); mInjector.setDisplayEventListenerLocked(getHandler().getLooper(), new LocalDisplayEventListener()); for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) { tryConnectDisplayLocked(physicalDisplayId); Loading Loading @@ -1052,12 +1058,33 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } private final class PhysicalDisplayEventReceiver extends DisplayEventReceiver { PhysicalDisplayEventReceiver(Looper looper) { public static class Injector { private ProxyDisplayEventReceiver mReceiver; public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) { mReceiver = new ProxyDisplayEventReceiver(looper, listener); } } public interface DisplayEventListener { void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected); void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId); } public static final class ProxyDisplayEventReceiver extends DisplayEventReceiver { private final DisplayEventListener mListener; ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) { super(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_DISPATCH); mListener = listener; } public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { mListener.onHotplug(timestampNanos, physicalDisplayId, connected); } public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { mListener.onConfigChanged(timestampNanos, physicalDisplayId, configId); } } @Override private final class LocalDisplayEventListener implements DisplayEventListener { public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { synchronized (getSyncRoot()) { if (connected) { Loading @@ -1067,8 +1094,6 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } } @Override public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { if (DEBUG) { Slog.d(TAG, "onConfigChanged(" Loading
services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +69 −6 Original line number Diff line number Diff line Loading @@ -83,6 +83,8 @@ public class LocalDisplayAdapterTest { private LinkedList<DisplayAddress.Physical> mAddresses = new LinkedList<>(); private Injector mInjector; @Before public void setUp() throws Exception { mMockitoSession = mockitoSession() Loading @@ -94,8 +96,9 @@ public class LocalDisplayAdapterTest { doReturn(mMockedResources).when(mMockedContext).getResources(); LocalServices.removeServiceForTest(LightsManager.class); LocalServices.addService(LightsManager.class, mMockedLightsManager); mInjector = new Injector(); mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler, mListener); mListener, mInjector); spyOn(mAdapter); doReturn(mMockedContext).when(mAdapter).getOverlayContext(); } Loading Loading @@ -222,7 +225,7 @@ public class LocalDisplayAdapterTest { display.configs = configs; display.activeConfig = 1; setUpDisplay(display); mAdapter.registerLocked(); mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(SurfaceControl.getActiveConfig(display.token)).isEqualTo(1); Loading Loading @@ -272,7 +275,7 @@ public class LocalDisplayAdapterTest { new int[Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS], 1000, 1000, 0); display.hdrCapabilities = changedHdrCapabilities; setUpDisplay(display); mAdapter.registerLocked(); mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(mListener.addedDisplays.size()).isEqualTo(1); Loading Loading @@ -308,7 +311,7 @@ public class LocalDisplayAdapterTest { final int[] changedColorModes = new int[]{Display.COLOR_MODE_DEFAULT}; display.colorModes = changedColorModes; setUpDisplay(display); mAdapter.registerLocked(); mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(mListener.addedDisplays.size()).isEqualTo(1); Loading @@ -322,6 +325,35 @@ public class LocalDisplayAdapterTest { assertThat(displayDeviceInfo.supportedColorModes).isEqualTo(changedColorModes); } @Test public void testDisplayChange_withStaleDesiredDisplayConfigSpecs() throws Exception { SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[]{ createFakeDisplayConfig(1920, 1080, 60f), createFakeDisplayConfig(1920, 1080, 50f) }; final int activeConfig = 0; FakeDisplay display = new FakeDisplay(PORT_A, configs, activeConfig); display.desiredDisplayConfigSpecs.defaultConfig = 1; setUpDisplay(display); updateAvailableDisplays(); mAdapter.registerLocked(); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); // Change the display display.configs = new SurfaceControl.DisplayConfig[]{ createFakeDisplayConfig(1920, 1080, 60f) }; // SurfaceFlinger can return a stale defaultConfig. Make sure this doesn't // trigger ArrayOutOfBoundsException. display.desiredDisplayConfigSpecs.defaultConfig = 1; setUpDisplay(display); updateAvailableDisplays(); mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); } private void assertDisplayDpi(DisplayDeviceInfo info, int expectedPort, float expectedXdpi, float expectedYDpi, Loading Loading @@ -356,6 +388,8 @@ public class LocalDisplayAdapterTest { public int[] colorModes = new int[]{ Display.COLOR_MODE_DEFAULT }; public Display.HdrCapabilities hdrCapabilities = new Display.HdrCapabilities(new int[0], 1000, 1000, 0); public SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs = new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f); private FakeDisplay(int port) { this.address = createDisplayAddress(port); Loading Loading @@ -387,7 +421,7 @@ public class LocalDisplayAdapterTest { () -> SurfaceControl.getDisplayColorModes(display.token)); doReturn(display.hdrCapabilities).when( () -> SurfaceControl.getHdrCapabilities(display.token)); doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f)) doReturn(display.desiredDisplayConfigSpecs) .when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token)); } Loading Loading @@ -422,7 +456,7 @@ public class LocalDisplayAdapterTest { return config; } private void waitForHandlerToComplete(Handler handler, long waitTimeMs) private static void waitForHandlerToComplete(Handler handler, long waitTimeMs) throws InterruptedException { final Object lock = new Object(); synchronized (lock) { Loading @@ -435,6 +469,35 @@ public class LocalDisplayAdapterTest { } } private class HotplugTransmitter { private final Handler mHandler; private final LocalDisplayAdapter.DisplayEventListener mListener; HotplugTransmitter(Looper looper, LocalDisplayAdapter.DisplayEventListener listener) { mHandler = new Handler(looper); mListener = listener; } public void sendHotplug(FakeDisplay display, boolean connected) throws InterruptedException { mHandler.post(() -> mListener.onHotplug(/* timestampNanos = */ 0, display.address.getPhysicalDisplayId(), connected)); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); } } private class Injector extends LocalDisplayAdapter.Injector { private HotplugTransmitter mTransmitter; @Override public void setDisplayEventListenerLocked(Looper looper, LocalDisplayAdapter.DisplayEventListener listener) { mTransmitter = new HotplugTransmitter(looper, listener); } public HotplugTransmitter getTransmitter() { return mTransmitter; } } private class TestListener implements DisplayAdapter.Listener { public ArrayList<DisplayDevice> addedDisplays = new ArrayList<>(); public ArrayList<DisplayDevice> changedDisplays = new ArrayList<>(); Loading