Add Display Category Rear

Use the rear display designation to expose as a rear display
through display manager.

Bug: 264611005
Test: atest com.android.server.display
Change-Id: Icbb72b4bb08032a1447bd9e9404be45ea355e28a
This commit is contained in:
Fiona Campbell
2023-01-16 14:43:37 +00:00
parent 9a0c93a4d3
commit fc15d209a7
9 changed files with 147 additions and 14 deletions

View File

@@ -114,6 +114,23 @@ public final class DisplayManager {
public static final String DISPLAY_CATEGORY_PRESENTATION =
"android.hardware.display.category.PRESENTATION";
/**
* Display category: Rear displays.
* <p>
* This category can be used to identify complementary internal displays that are facing away
* from the user.
* Certain applications may present to this display.
* Similar to presentation displays.
* </p>
*
* @see android.app.Presentation
* @see Display#FLAG_PRESENTATION
* @see #getDisplays(String)
* @hide
*/
public static final String DISPLAY_CATEGORY_REAR =
"android.hardware.display.category.REAR";
/**
* Display category: All displays, including disabled displays.
* <p>
@@ -619,11 +636,19 @@ public final class DisplayManager {
synchronized (mLock) {
try {
if (DISPLAY_CATEGORY_PRESENTATION.equals(category)) {
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_EXTERNAL);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL);
addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI,
Display.FLAG_PRESENTATION);
addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_EXTERNAL,
Display.FLAG_PRESENTATION);
addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY,
Display.FLAG_PRESENTATION);
addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL,
Display.FLAG_PRESENTATION);
addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL,
Display.FLAG_PRESENTATION);
} else if (DISPLAY_CATEGORY_REAR.equals(category)) {
addDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL,
Display.FLAG_REAR);
} else if (category == null
|| DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) {
addAllDisplaysLocked(mTempDisplays, displayIds);
@@ -644,15 +669,16 @@ public final class DisplayManager {
}
}
private void addPresentationDisplaysLocked(
ArrayList<Display> displays, int[] displayIds, int matchType) {
for (int i = 0; i < displayIds.length; i++) {
if (displayIds[i] == DEFAULT_DISPLAY) {
private void addDisplaysLocked(
ArrayList<Display> displays, int[] displayIds, int matchType, int flagMask) {
for (int displayId : displayIds) {
if (displayId == DEFAULT_DISPLAY) {
continue;
}
Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
Display display = getOrCreateDisplayLocked(displayId, /* assumeValid= */ true);
if (display != null
&& (display.getFlags() & Display.FLAG_PRESENTATION) != 0
&& (display.getFlags() & flagMask) == flagMask
&& display.getType() == matchType) {
displays.add(display);
}

View File

@@ -359,6 +359,17 @@ public final class Display {
*/
public static final int FLAG_STEAL_TOP_FOCUS_DISABLED = 1 << 12;
/**
* Display flag: Indicates that the display is a rear display.
* <p>
* This flag identifies complementary displays that are facing away from the user.
* </p>
*
* @hide
* @see #getFlags()
*/
public static final int FLAG_REAR = 1 << 13;
/**
* Display flag: Indicates that the contents of the display should not be scaled
* to fit the physical screen dimensions. Used for development only to emulate

View File

@@ -906,6 +906,9 @@ public final class DisplayInfo implements Parcelable {
if ((flags & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
result.append(", FLAG_TOUCH_FEEDBACK_DISABLED");
}
if ((flags & Display.FLAG_REAR) != 0) {
result.append(", FLAG_REAR_DISPLAY");
}
return result.toString();
}
}

View File

@@ -118,6 +118,7 @@ class DeviceStateToLayoutMap {
final int state = l.getState().intValue();
final Layout layout = createLayout(state);
for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
assert layout != null;
Layout.Display display = layout.createDisplayLocked(
DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
d.isDefaultDisplay(),

View File

@@ -31,6 +31,7 @@ import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
import com.android.server.display.layout.Layout;
import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
@@ -152,6 +153,10 @@ final class LogicalDisplay {
// the {@link mIsEnabled} is changing, or the underlying mPrimiaryDisplayDevice is changing.
private boolean mIsInTransition;
// Indicates the position of the display, POSITION_UNKNOWN could mean it hasn't been specified,
// or this is a virtual display etc.
private int mPosition = Layout.Display.POSITION_UNKNOWN;
/**
* The ID of the brightness throttling data that should be used. This can change e.g. in
* concurrent displays mode in which a stricter brightness throttling policy might need to be
@@ -170,6 +175,13 @@ final class LogicalDisplay {
mBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_BRIGHTNESS_THROTTLING_DATA_ID;
}
public void setPositionLocked(int position) {
mPosition = position;
}
public int getPositionLocked() {
return mPosition;
}
/**
* Gets the logical display id of this logical display.
*
@@ -424,6 +436,11 @@ final class LogicalDisplay {
mBaseDisplayInfo.roundedCorners = deviceInfo.roundedCorners;
mBaseDisplayInfo.installOrientation = deviceInfo.installOrientation;
mBaseDisplayInfo.displayShape = deviceInfo.displayShape;
if (mPosition == Layout.Display.POSITION_REAR) {
mBaseDisplayInfo.flags |= Display.FLAG_REAR;
}
mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo.set(null);
}
@@ -814,6 +831,7 @@ final class LogicalDisplay {
pw.println("mIsEnabled=" + mIsEnabled);
pw.println("mIsInTransition=" + mIsInTransition);
pw.println("mLayerStack=" + mLayerStack);
pw.println("mPosition=" + mPosition);
pw.println("mHasContent=" + mHasContent);
pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}");
pw.println("mRequestedColorMode=" + mRequestedColorMode);

View File

@@ -977,6 +977,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
// Now that we have a display-device, we need a LogicalDisplay to map it to. Find the
// right one, if it doesn't exist, create a new one.
final int logicalDisplayId = displayLayout.getLogicalDisplayId();
LogicalDisplay newDisplay = getDisplayLocked(logicalDisplayId);
if (newDisplay == null) {
newDisplay = createNewLogicalDisplayLocked(
@@ -989,6 +990,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
newDisplay.swapDisplaysLocked(oldDisplay);
}
newDisplay.setPositionLocked(displayLayout.getPosition());
setEnabledLocked(newDisplay, displayLayout.isEnabled());
newDisplay.setBrightnessThrottlingDataIdLocked(
displayLayout.getBrightnessThrottlingMapId() == null

View File

@@ -18,6 +18,8 @@ package com.android.server.display.layout;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.display.layout.Layout.Display.POSITION_UNKNOWN;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Slog;
@@ -78,6 +80,22 @@ public class Layout {
public Display createDisplayLocked(
@NonNull DisplayAddress address, boolean isDefault, boolean isEnabled,
DisplayIdProducer idProducer, String brightnessThrottlingMapId) {
return createDisplayLocked(address, isDefault, isEnabled, idProducer,
brightnessThrottlingMapId, POSITION_UNKNOWN);
}
/**
* Creates a simple 1:1 LogicalDisplay mapping for the specified DisplayDevice.
*
* @param address Address of the device.
* @param isDefault Indicates if the device is meant to be the default display.
* @param isEnabled Indicates if this display is usable and can be switched on
* @param position Indicates the position this display is facing in this layout.
* @return The new layout.
*/
public Display createDisplayLocked(
@NonNull DisplayAddress address, boolean isDefault, boolean isEnabled,
DisplayIdProducer idProducer, String brightnessThrottlingMapId, int position) {
if (contains(address)) {
Slog.w(TAG, "Attempting to add second definition for display-device: " + address);
return null;
@@ -95,7 +113,7 @@ public class Layout {
// same logical display ID.
final int logicalDisplayId = idProducer.getId(isDefault);
final Display display = new Display(address, logicalDisplayId, isEnabled,
brightnessThrottlingMapId);
brightnessThrottlingMapId, position);
mDisplays.add(display);
return display;
@@ -204,11 +222,11 @@ public class Layout {
private final String mBrightnessThrottlingMapId;
Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled,
String brightnessThrottlingMapId) {
String brightnessThrottlingMapId, int position) {
mAddress = address;
mLogicalDisplayId = logicalDisplayId;
mIsEnabled = isEnabled;
mPosition = POSITION_UNKNOWN;
mPosition = position;
mBrightnessThrottlingMapId = brightnessThrottlingMapId;
}
@@ -272,5 +290,9 @@ public class Layout {
public String getBrightnessThrottlingMapId() {
return mBrightnessThrottlingMapId;
}
public int getPosition() {
return mPosition;
}
}
}

View File

@@ -111,6 +111,14 @@ public class DeviceStateToLayoutMapTest {
assertEquals(testLayout, configLayout);
}
@Test
public void testRearDisplayLayout() {
Layout configLayout = mDeviceStateToLayoutMap.get(2);
assertEquals(Layout.Display.POSITION_FRONT, configLayout.getAt(0).getPosition());
assertEquals(Layout.Display.POSITION_REAR, configLayout.getAt(1).getPosition());
}
////////////////////
// Helper Methods //
////////////////////

View File

@@ -19,6 +19,7 @@ package com.android.server.display;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY_GROUP;
import static android.view.Display.FLAG_REAR;
import static android.view.Display.TYPE_EXTERNAL;
import static android.view.Display.TYPE_INTERNAL;
import static android.view.Display.TYPE_VIRTUAL;
@@ -30,6 +31,8 @@ import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_REM
import static com.android.server.display.DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED;
import static com.android.server.display.layout.Layout.Display.POSITION_REAR;
import static com.android.server.display.layout.Layout.Display.POSITION_UNKNOWN;
import static com.google.common.truth.Truth.assertThat;
@@ -778,6 +781,45 @@ public class LogicalDisplayMapperTest {
assertFalse(display2.isEnabledLocked());
}
@Test
public void testDisplayFlagRear() {
DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800,
FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
DisplayDevice device2 = createDisplayDevice(TYPE_INTERNAL, 600, 800,
FLAG_REAR);
Layout layout = new Layout();
layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address,
true, true, mIdProducer, /* brightnessThrottlingMapId= */ null);
layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address,
false, true, mIdProducer, /* brightnessThrottlingMapId= */ null,
POSITION_REAR);
when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(layout);
when(mDeviceStateToLayoutMapSpy.size()).thenReturn(1);
LogicalDisplay display1 = add(device1);
assertEquals(info(display1).address, info(device1).address);
assertEquals(DEFAULT_DISPLAY, id(display1));
LogicalDisplay display2 = add(device2);
assertEquals(info(display2).address, info(device2).address);
// We can only have one default display
assertEquals(DEFAULT_DISPLAY, id(display1));
mLogicalDisplayMapper.setDeviceStateLocked(0, false);
advanceTime(1000);
mLogicalDisplayMapper.onBootCompleted();
advanceTime(1000);
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
assertEquals(POSITION_UNKNOWN,
mLogicalDisplayMapper.getDisplayLocked(device1).getPositionLocked());
assertEquals(POSITION_REAR,
mLogicalDisplayMapper.getDisplayLocked(device2).getPositionLocked());
}
/////////////////
// Helper Methods