Merge "LocalDisplayAdapter test for stale DesiredDisplayConfigSpecs"
This commit is contained in:
committed by
Android (Google) Code Review
commit
55d4d2e817
@@ -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);
|
||||
@@ -1052,12 +1058,33 @@ final class LocalDisplayAdapter extends DisplayAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private final class PhysicalDisplayEventReceiver extends DisplayEventReceiver {
|
||||
PhysicalDisplayEventReceiver(Looper looper) {
|
||||
super(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_DISPATCH);
|
||||
public static class Injector {
|
||||
private ProxyDisplayEventReceiver mReceiver;
|
||||
public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) {
|
||||
mReceiver = new ProxyDisplayEventReceiver(looper, listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private final class LocalDisplayEventListener implements DisplayEventListener {
|
||||
public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
|
||||
synchronized (getSyncRoot()) {
|
||||
if (connected) {
|
||||
@@ -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("
|
||||
|
||||
@@ -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()
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -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<>();
|
||||
|
||||
Reference in New Issue
Block a user