summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/display/DisplayAdapter.java16
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java7
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java15
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java64
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java4
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java76
6 files changed, 143 insertions, 39 deletions
diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
index 69bc66fea56c..155f82a421ae 100644
--- a/services/core/java/com/android/server/display/DisplayAdapter.java
+++ b/services/core/java/com/android/server/display/DisplayAdapter.java
@@ -19,6 +19,7 @@ package com.android.server.display;
import android.content.Context;
import android.os.Handler;
import android.view.Display;
+import android.view.SurfaceControl;
import com.android.server.display.feature.DisplayManagerFlags;
@@ -138,6 +139,21 @@ abstract class DisplayAdapter {
vsyncRate, /* isSynthetic= */ false, alternativeRefreshRates, supportedHdrTypes);
}
+ static int getPowerModeForState(int state) {
+ switch (state) {
+ case Display.STATE_OFF:
+ return SurfaceControl.POWER_MODE_OFF;
+ case Display.STATE_DOZE:
+ return SurfaceControl.POWER_MODE_DOZE;
+ case Display.STATE_DOZE_SUSPEND:
+ return SurfaceControl.POWER_MODE_DOZE_SUSPEND;
+ case Display.STATE_ON_SUSPEND:
+ return SurfaceControl.POWER_MODE_ON_SUSPEND;
+ default:
+ return SurfaceControl.POWER_MODE_NORMAL;
+ }
+ }
+
public interface Listener {
void onDisplayDeviceEvent(DisplayDevice device, int event);
void onTraversalRequested();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 258c95582e3a..d402f010281f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2618,8 +2618,7 @@ public final class DisplayManagerService extends SystemService {
// Blank or unblank the display immediately to match the state requested
// by the display power controller (if known).
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
- if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0
- || android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
+ if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display == null) {
return null;
@@ -5580,9 +5579,7 @@ public final class DisplayManagerService extends SystemService {
final DisplayDevice displayDevice = mLogicalDisplayMapper.getDisplayLocked(
id).getPrimaryDisplayDeviceLocked();
final int flags = displayDevice.getDisplayDeviceInfoLocked().flags;
- if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0
- || android.companion.virtualdevice.flags.Flags
- .correctVirtualDisplayPowerState()) {
+ if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
final DisplayPowerController displayPowerController =
mDisplayPowerControllers.get(id);
if (displayPowerController != null) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 551202c20cbb..7b714ad2bd9e 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -208,21 +208,6 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
- static int getPowerModeForState(int state) {
- switch (state) {
- case Display.STATE_OFF:
- return SurfaceControl.POWER_MODE_OFF;
- case Display.STATE_DOZE:
- return SurfaceControl.POWER_MODE_DOZE;
- case Display.STATE_DOZE_SUSPEND:
- return SurfaceControl.POWER_MODE_DOZE_SUSPEND;
- case Display.STATE_ON_SUSPEND:
- return SurfaceControl.POWER_MODE_ON_SUSPEND;
- default:
- return SurfaceControl.POWER_MODE_NORMAL;
- }
- }
-
private final class LocalDisplayDevice extends DisplayDevice {
private final long mPhysicalDisplayId;
private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>();
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index e7939bb50ece..ac03a93ca9e1 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -113,6 +113,11 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
public void destroyDisplay(IBinder displayToken) {
DisplayControl.destroyVirtualDisplay(displayToken);
}
+
+ @Override
+ public void setDisplayPowerMode(IBinder displayToken, int mode) {
+ SurfaceControl.setDisplayPowerMode(displayToken, mode);
+ }
}, featureFlags);
}
@@ -340,6 +345,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
private Display.Mode mMode;
private int mDisplayIdToMirror;
private boolean mIsWindowManagerMirroring;
+ private final boolean mNeverBlank;
private final DisplayCutout mDisplayCutout;
private final float mDefaultBrightness;
private final float mDimBrightness;
@@ -371,7 +377,11 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mCallback = callback;
mProjection = projection;
mMediaProjectionCallback = mediaProjectionCallback;
- if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
+ // Private non-mirror displays are never blank and always on.
+ mNeverBlank = (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0
+ && (flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0;
+ if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()
+ && !mNeverBlank) {
// The display's power state depends on the power state of the state of its
// display / power group, which we don't know here. Initializing to UNKNOWN allows
// the first call to requestDisplayStateLocked() to set the correct state.
@@ -471,7 +481,15 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
@Override
public Runnable requestDisplayStateLocked(int state, float brightnessState,
float sdrBrightnessState, DisplayOffloadSessionImpl displayOffloadSession) {
+ Runnable runnable = null;
if (state != mDisplayState) {
+ Slog.d(TAG, "Changing state of virtual display " + mName + " from "
+ + Display.stateToString(mDisplayState) + " to "
+ + Display.stateToString(state));
+ if (state != Display.STATE_ON && state != Display.STATE_OFF) {
+ Slog.wtf(TAG, "Unexpected display state for Virtual Display: "
+ + Display.stateToString(state));
+ }
mDisplayState = state;
mInfo = null;
sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
@@ -480,6 +498,15 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
} else {
mCallback.dispatchDisplayResumed();
}
+
+ if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
+ final IBinder token = getDisplayTokenLocked();
+ runnable = () -> {
+ final int mode = getPowerModeForState(state);
+ Slog.d(TAG, "Requesting power mode for display " + mName + " to " + mode);
+ mSurfaceControlDisplayFactory.setDisplayPowerMode(token, mode);
+ };
+ }
}
if (android.companion.virtualdevice.flags.Flags.deviceAwareDisplayPower()
&& mBrightnessListener != null
@@ -488,7 +515,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mCurrentBrightness = brightnessState;
mCallback.dispatchRequestedBrightnessChanged(mCurrentBrightness);
}
- return null;
+ return runnable;
}
@Override
@@ -572,23 +599,14 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mInfo.yDpi = mDensityDpi;
mInfo.presentationDeadlineNanos = 1000000000L / (int) getRefreshRate(); // 1 frame
mInfo.flags = 0;
- if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
- if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
- mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
- }
- if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0) {
- mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
- }
- } else {
- if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
- mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
- | DisplayDeviceInfo.FLAG_NEVER_BLANK;
- }
- if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
- mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
- } else {
- mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
- }
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
+ }
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
+ }
+ if (mNeverBlank) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_NEVER_BLANK;
}
if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
@@ -782,5 +800,13 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
* @param displayToken The display token for the display to be destroyed.
*/
void destroyDisplay(IBinder displayToken);
+
+ /**
+ * Set the display power mode in SurfaceFlinger.
+ *
+ * @param displayToken The display token for the display.
+ * @param mode the SurfaceControl power mode, e.g. {@link SurfaceControl#POWER_MODE_OFF}.
+ */
+ void setDisplayPowerMode(IBinder displayToken, int mode);
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index c151732cec66..65585d06ff06 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -332,6 +332,10 @@ public class DisplayManagerServiceTest {
@Override
public void destroyDisplay(IBinder displayToken) {
}
+
+ @Override
+ public void setDisplayPowerMode(IBinder displayToken, int mode) {
+ }
}, flags);
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
index 9287b3004279..0bef3b89547f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
@@ -21,19 +21,29 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.display.DisplayManager;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.media.projection.IMediaProjection;
+import android.os.Binder;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.Process;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableContext;
import android.view.Display;
import android.view.Surface;
+import android.view.SurfaceControl;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -67,6 +77,9 @@ public class VirtualDisplayAdapterTest {
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getInstrumentation().getContext());
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Mock
private VirtualDisplayAdapter.SurfaceControlDisplayFactory mMockSufaceControlDisplayFactory;
@@ -380,6 +393,69 @@ public class VirtualDisplayAdapterTest {
}
}
+ @EnableFlags(
+ android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE)
+ @Test
+ public void neverBlankDisplay_alwaysOn() {
+ // A non-public non-mirror display is considered never blank.
+ DisplayDevice device = mAdapter.createVirtualDisplayLocked(mMockCallback,
+ /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+ "uniqueId", /* surface= */ mSurfaceMock, /* flags= */ 0,
+ mVirtualDisplayConfigMock);
+
+ DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+ assertThat(info.state).isEqualTo(Display.STATE_ON);
+ assertThat(info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK)
+ .isEqualTo(DisplayDeviceInfo.FLAG_NEVER_BLANK);
+ }
+
+ @EnableFlags(
+ android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE)
+ @Test
+ public void virtualDisplayStateChange_propagatesToSurfaceControl() throws Exception {
+ final String uniqueId = "uniqueId";
+ final IBinder displayToken = new Binder();
+ when(mMockSufaceControlDisplayFactory.createDisplay(
+ any(), anyBoolean(), eq(uniqueId), anyFloat()))
+ .thenReturn(displayToken);
+
+ // The display needs to be public, otherwise it will be considered never blank.
+ DisplayDevice device = mAdapter.createVirtualDisplayLocked(mMockCallback,
+ /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+ uniqueId, /* surface= */ mSurfaceMock, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
+ mVirtualDisplayConfigMock);
+
+ DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+ assertThat(info.state).isEqualTo(Display.STATE_UNKNOWN);
+ assertThat(info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK).isEqualTo(0);
+
+ // Any initial state change is processed because the display state is initially UNKNOWN
+ Runnable stateOnRunnable = device.requestDisplayStateLocked(
+ Display.STATE_ON, /* brightnessState= */ 1.0f, /* sdrBrightnessState= */ 1.0f,
+ /* displayOffloadSession= */ null);
+ assertThat(stateOnRunnable).isNotNull();
+ stateOnRunnable.run();
+ verify(mMockSufaceControlDisplayFactory)
+ .setDisplayPowerMode(displayToken, SurfaceControl.POWER_MODE_NORMAL);
+ verify(mMockCallback).onResumed();
+
+ // Requesting the same display state is a no-op
+ Runnable stateOnSecondRunnable = device.requestDisplayStateLocked(
+ Display.STATE_ON, /* brightnessState= */ 1.0f, /* sdrBrightnessState= */ 1.0f,
+ /* displayOffloadSession= */ null);
+ assertThat(stateOnSecondRunnable).isNull();
+
+ // A change to the display state is processed
+ Runnable stateOffRunnable = device.requestDisplayStateLocked(
+ Display.STATE_OFF, /* brightnessState= */ 1.0f, /* sdrBrightnessState= */ 1.0f,
+ /* displayOffloadSession= */ null);
+ assertThat(stateOffRunnable).isNotNull();
+ stateOffRunnable.run();
+ verify(mMockSufaceControlDisplayFactory)
+ .setDisplayPowerMode(displayToken, SurfaceControl.POWER_MODE_OFF);
+ verify(mMockCallback).onPaused();
+ }
+
private IVirtualDisplayCallback createCallback() {
return new IVirtualDisplayCallback.Stub() {