Fix boot animation when device is folded

- Initialize internal logical displays as disabled
- Postpone device state transition until boot is completed

Bug: 193821864
Test: atest LogicalDisplayMapperTest
Change-Id: I5a7c7c3fe6d07d22733d98c2ff2dbe6a9392f05c
This commit is contained in:
Piotr Wilczyński
2022-12-22 12:19:45 +00:00
parent 85a3f5050d
commit 2766b1c8f1
3 changed files with 58 additions and 5 deletions

View File

@@ -94,6 +94,10 @@ class DeviceStateToLayoutMap {
return layout; return layout;
} }
int size() {
return mLayoutMap.size();
}
/** /**
* Reads display-layout-configuration files to get the layouts to use for this device. * Reads display-layout-configuration files to get the layouts to use for this device.
*/ */

View File

@@ -405,12 +405,23 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
void setDeviceStateLocked(int state, boolean isOverrideActive) { void setDeviceStateLocked(int state, boolean isOverrideActive) {
Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState
+ ", interactive=" + mInteractive + ", mBootCompleted=" + mBootCompleted); + ", 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 // 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 // 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 // on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be
// temporarily turned off. // temporarily turned off.
resetLayoutLocked(mDeviceState, state, /* transitionValue= */ true); resetLayoutLocked(mDeviceState, state, /* transitionValue= */ true);
mPendingDeviceState = state;
final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState, final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState,
mInteractive, mBootCompleted); mInteractive, mBootCompleted);
final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState, final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState,
@@ -457,6 +468,9 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
void onBootCompleted() { void onBootCompleted() {
synchronized (mSyncRoot) { synchronized (mSyncRoot) {
mBootCompleted = true; mBootCompleted = true;
if (mPendingDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) {
setDeviceStateLocked(mPendingDeviceState, false);
}
} }
} }
@@ -982,6 +996,15 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
final int layerStack = assignLayerStackLocked(displayId); final int layerStack = assignLayerStackLocked(displayId);
final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device); final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
display.updateLocked(mDisplayDeviceRepo); 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); mLogicalDisplays.put(displayId, display);
return display; return display;
} }

View File

@@ -18,6 +18,7 @@ package com.android.server.display;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY_GROUP; 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_INTERNAL;
import static android.view.Display.TYPE_VIRTUAL; import static android.view.Display.TYPE_VIRTUAL;
@@ -177,7 +178,7 @@ public class LogicalDisplayMapperTest {
@Test @Test
public void testDisplayDeviceAddAndRemove_NonInternalTypes() { public void testDisplayDeviceAddAndRemove_NonInternalTypes() {
testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_EXTERNAL); testDisplayDeviceAddAndRemove_NonInternal(TYPE_EXTERNAL);
testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_WIFI); testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_WIFI);
testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_OVERLAY); testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_OVERLAY);
testDisplayDeviceAddAndRemove_NonInternal(TYPE_VIRTUAL); testDisplayDeviceAddAndRemove_NonInternal(TYPE_VIRTUAL);
@@ -222,7 +223,7 @@ public class LogicalDisplayMapperTest {
@Test @Test
public void testDisplayDeviceAddAndRemove_OneExternalDefault() { 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); FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
// add // add
@@ -272,7 +273,7 @@ public class LogicalDisplayMapperTest {
public void testGetDisplayIdsLocked() { public void testGetDisplayIdsLocked() {
add(createDisplayDevice(TYPE_INTERNAL, 600, 800, add(createDisplayDevice(TYPE_INTERNAL, 600, 800,
FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); 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)); add(createDisplayDevice(TYPE_VIRTUAL, 600, 800, 0));
int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID, int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID,
@@ -558,7 +559,7 @@ public class LogicalDisplayMapperTest {
layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address, layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address,
true, true, mIdProducer); true, true, mIdProducer);
layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address, layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address,
false, false, mIdProducer); false, true, mIdProducer);
when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(layout); when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(layout);
layout = new Layout(); layout = new Layout();
@@ -569,6 +570,8 @@ public class LogicalDisplayMapperTest {
when(mDeviceStateToLayoutMapSpy.get(1)).thenReturn(layout); when(mDeviceStateToLayoutMapSpy.get(1)).thenReturn(layout);
when(mDeviceStateToLayoutMapSpy.get(2)).thenReturn(layout); when(mDeviceStateToLayoutMapSpy.get(2)).thenReturn(layout);
when(mDeviceStateToLayoutMapSpy.size()).thenReturn(4);
LogicalDisplay display1 = add(device1); LogicalDisplay display1 = add(device1);
assertEquals(info(display1).address, info(device1).address); assertEquals(info(display1).address, info(device1).address);
assertEquals(DEFAULT_DISPLAY, id(display1)); assertEquals(DEFAULT_DISPLAY, id(display1));
@@ -580,8 +583,14 @@ public class LogicalDisplayMapperTest {
mLogicalDisplayMapper.setDeviceStateLocked(0, false); mLogicalDisplayMapper.setDeviceStateLocked(0, false);
advanceTime(1000); advanceTime(1000);
// The new state is not applied until the boot is completed
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked()); assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
mLogicalDisplayMapper.onBootCompleted();
advanceTime(1000);
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked());
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked()); assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
@@ -722,6 +731,23 @@ public class LogicalDisplayMapperTest {
assertEquals(3, threeDisplaysEnabled.length); 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 // Helper Methods
///////////////// /////////////////