diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java index 9dd2f8408c560..b9ca57e70b3e6 100644 --- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java +++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java @@ -76,6 +76,10 @@ class DeviceStateToLayoutMap { return layout; } + int size() { + return mLayoutMap.size(); + } + private Layout createLayout(int state) { if (mLayoutMap.contains(state)) { Slog.e(TAG, "Attempted to create a second layout for state " + state); diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index bf576b8909f24..375e51c672b53 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -372,12 +372,23 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { void setDeviceStateLocked(int state, boolean isOverrideActive) { Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState + ", interactive=" + mInteractive + ", mBootCompleted=" + mBootCompleted); + mPendingDeviceState = state; + + if (!mBootCompleted) { + // The boot animation might still be in progress, we do not want to switch states now + // as the boot animation would end up with an incorrect size. + if (DEBUG) { + Slog.d(TAG, "Postponing transition to state: " + mPendingDeviceState + + " until boot is completed"); + } + return; + } + // As part of a state transition, we may need to turn off some displays temporarily so that // the transition is smooth. Plus, on some devices, only one internal displays can be // on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be // temporarily turned off. resetLayoutLocked(mDeviceState, state, /* isStateChangeStarting= */ true); - mPendingDeviceState = state; final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState, mInteractive, mBootCompleted); final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState, @@ -424,6 +435,9 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { void onBootCompleted() { synchronized (mSyncRoot) { mBootCompleted = true; + if (mPendingDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) { + setDeviceStateLocked(mPendingDeviceState, /* isOverrideActive= */ false); + } } } @@ -926,6 +940,15 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { final int layerStack = assignLayerStackLocked(displayId); final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device); display.updateLocked(mDisplayDeviceRepo); + + final DisplayInfo info = display.getDisplayInfoLocked(); + if (info.type == Display.TYPE_INTERNAL && mDeviceStateToLayoutMap.size() > 1) { + // If this is an internal display and the device uses a display layout configuration, + // the display should be disabled as later we will receive a device state update, which + // will tell us which internal displays should be enabled and which should be disabled. + display.setEnabledLocked(false); + } + mLogicalDisplays.put(displayId, display); return display; } diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index 638637d544de0..6790ad9a5da15 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -18,6 +18,7 @@ package com.android.server.display; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY_GROUP; +import static android.view.Display.TYPE_EXTERNAL; import static android.view.Display.TYPE_INTERNAL; import static android.view.Display.TYPE_VIRTUAL; @@ -173,7 +174,7 @@ public class LogicalDisplayMapperTest { @Test public void testDisplayDeviceAddAndRemove_NonInternalTypes() { - testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_EXTERNAL); + testDisplayDeviceAddAndRemove_NonInternal(TYPE_EXTERNAL); testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_WIFI); testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_OVERLAY); testDisplayDeviceAddAndRemove_NonInternal(TYPE_VIRTUAL); @@ -218,7 +219,7 @@ public class LogicalDisplayMapperTest { @Test public void testDisplayDeviceAddAndRemove_OneExternalDefault() { - DisplayDevice device = createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, + DisplayDevice device = createDisplayDevice(TYPE_EXTERNAL, 600, 800, FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); // add @@ -268,7 +269,7 @@ public class LogicalDisplayMapperTest { public void testGetDisplayIdsLocked() { add(createDisplayDevice(TYPE_INTERNAL, 600, 800, FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - add(createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, 0)); + add(createDisplayDevice(TYPE_EXTERNAL, 600, 800, 0)); add(createDisplayDevice(TYPE_VIRTUAL, 600, 800, 0)); int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID, @@ -460,7 +461,7 @@ public class LogicalDisplayMapperTest { Layout layout = new Layout(); layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address, true, true); - layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address, false, false); + layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address, false, true); when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(layout); layout = new Layout(); @@ -469,6 +470,8 @@ public class LogicalDisplayMapperTest { when(mDeviceStateToLayoutMapSpy.get(1)).thenReturn(layout); when(mDeviceStateToLayoutMapSpy.get(2)).thenReturn(layout); + when(mDeviceStateToLayoutMapSpy.size()).thenReturn(4); + LogicalDisplay display1 = add(device1); assertEquals(info(display1).address, info(device1).address); assertEquals(DEFAULT_DISPLAY, id(display1)); @@ -481,8 +484,15 @@ public class LogicalDisplayMapperTest { mLogicalDisplayMapper.setDeviceStateLocked(0, false); mLooper.moveTimeForward(1000); mLooper.dispatchAll(); + // The new state is not applied until the boot is completed assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked()); + + mLogicalDisplayMapper.onBootCompleted(); + mLooper.moveTimeForward(1000); + mLooper.dispatchAll(); + assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked()); + assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked()); @@ -623,6 +633,23 @@ public class LogicalDisplayMapperTest { assertEquals(3, threeDisplaysEnabled.length); } + @Test + public void testCreateNewLogicalDisplay() { + DisplayDevice device1 = createDisplayDevice(TYPE_EXTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + when(mDeviceStateToLayoutMapSpy.size()).thenReturn(1); + LogicalDisplay display1 = add(device1); + + assertTrue(display1.isEnabledLocked()); + + DisplayDevice device2 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + when(mDeviceStateToLayoutMapSpy.size()).thenReturn(2); + LogicalDisplay display2 = add(device2); + + assertFalse(display2.isEnabledLocked()); + } + ///////////////// // Helper Methods /////////////////